commit 80aa9874b7efa59909bfb46ba240f1010f48fd71 Author: Ben S Date: Sun Oct 26 17:07:10 2014 +0000 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..fdbd29f --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.pbxproj -crlf -diff -merge diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a31158 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# xcode noise +build/* +*.pbxuser +xcuserdata +*.mode1v3 + +# osx noise +.DS_Store +profile diff --git a/Rust.xcodeproj/project.pbxproj b/Rust.xcodeproj/project.pbxproj new file mode 100644 index 0000000..07ca88d --- /dev/null +++ b/Rust.xcodeproj/project.pbxproj @@ -0,0 +1,173 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + B55C16E319FC0D3800FE9D6A /* rust.mm in Sources */ = {isa = PBXBuildFile; fileRef = B55C16E119FC0D3800FE9D6A /* rust.mm */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5F05134505A0957400BD0E76 /* info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = info.plist; sourceTree = ""; }; + B55C16E119FC0D3800FE9D6A /* rust.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = rust.mm; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + 089C166AFE841209C02AAC07 /* Hello World */ = { + isa = PBXGroup; + children = ( + 08FB77ADFE841716C02AAC07 /* Source */, + 5F05134505A0957400BD0E76 /* info.plist */, + ); + name = "Hello World"; + sourceTree = ""; + }; + 08FB77ADFE841716C02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + B55C16E119FC0D3800FE9D6A /* rust.mm */, + ); + name = Source; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5F05133905A0957400BD0E76 /* Rust */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2E4F91CD0863164B009D6578 /* Build configuration list for PBXNativeTarget "Rust" */; + buildPhases = ( + 5F05133F05A0957400BD0E76 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Rust; + productInstallPath = "$(HOME)/Library/Bundles"; + productName = "Hello World"; + productReference = B57F6C2519FD60C000FDB959 /* Rust.bblm */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 089C1669FE841209C02AAC07 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0610; + }; + buildConfigurationList = 2E4F91D10863164B009D6578 /* Build configuration list for PBXProject "Rust" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + en, + ); + mainGroup = 089C166AFE841209C02AAC07 /* Hello World */; + productRefGroup = 089C166AFE841209C02AAC07 /* Hello World */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5F05133905A0957400BD0E76 /* Rust */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 5F05133F05A0957400BD0E76 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B55C16E319FC0D3800FE9D6A /* rust.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 2E4F91CE0863164B009D6578 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + INFOPLIST_FILE = Info.plist; + INSTALL_MODE_FLAG = "ug+w,o-w,a+rX"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + OTHER_CFLAGS = ""; + PRODUCT_NAME = Rust; + SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; + SDKROOT = macosx10.10; + USER_HEADER_SEARCH_PATHS = "/Volumes/BBEdit\\ SDK/Interfaces/Language\\ Modules/"; + WRAPPER_EXTENSION = bblm; + }; + name = Debug; + }; + 2E4F91CF0863164B009D6578 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + INFOPLIST_FILE = Info.plist; + INSTALL_MODE_FLAG = "ug+w,o-w,a+rX"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + OTHER_CFLAGS = ""; + PRODUCT_NAME = Rust; + SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; + SDKROOT = macosx10.10; + USER_HEADER_SEARCH_PATHS = "/Volumes/BBEdit\\ SDK/Interfaces/Language\\ Modules/"; + WRAPPER_EXTENSION = bblm; + }; + name = Release; + }; + 2E4F91D20863164B009D6578 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx10.10; + VALID_ARCHS = i386; + }; + name = Debug; + }; + 2E4F91D30863164B009D6578 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + SDKROOT = macosx10.10; + VALID_ARCHS = i386; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2E4F91CD0863164B009D6578 /* Build configuration list for PBXNativeTarget "Rust" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2E4F91CE0863164B009D6578 /* Debug */, + 2E4F91CF0863164B009D6578 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 2E4F91D10863164B009D6578 /* Build configuration list for PBXProject "Rust" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2E4F91D20863164B009D6578 /* Debug */, + 2E4F91D30863164B009D6578 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + }; + rootObject = 089C1669FE841209C02AAC07 /* Project object */; +} diff --git a/Rust.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Rust.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..d80278e --- /dev/null +++ b/Rust.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/info.plist b/info.plist new file mode 100644 index 0000000..0b24830 --- /dev/null +++ b/info.plist @@ -0,0 +1,173 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + me.bsago.bblm.rust + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + BBLM + CFBundleVersion + 8.0 + CSResourcesFileMapped + + com.barebones.bblminfo + + + BBLMCanGuessLanguage + + BBLMColorsSyntax + + BBLMDroppedFilePathStyle + POSIX + BBLMCommentLineDefault + // + BBLMCommentPrefixDefault + /* + BBLMCommentSuffixDefault + */ + BBLMIsCaseSensitive + + BBLMRunNames + + me.bsago.bblm.rust.lifetime + 'lifetime + me.bsago.bblm.rust.identifier + Identifier + me.bsago.bblm.rust.attribute + #[attribute] + + BBLMRunColors + + me.bsago.bblm.rust.lifetime + rgb(133, 20, 75) + me.bsago.bblm.rust.attribute + rgb(177, 13, 201) + me.bsago.bblm.rust.identifier + rgb(61, 153, 112) + + BBLMKeywords + + + RunKind + com.barebones.bblm.keyword + Keywords + + as + box + break + continue + crate + else + enum + extern + false + fn + for + if + impl + in + let + loop + macro_rules! + match + mod + mut + priv + proc + pub + ref + return + self + static + struct + super + trait + true + type + unsafe + use + while + + + + RunKind + com.barebones.bblm.predefined-symbol + Keywords + + assert + bool + char + debug + env + error + externfn + f32 + f64 + fail + float + fmt + i16 + i32 + i64 + i8 + include + include_bin + include_str + info + int + proto + str + stringify + u16 + u32 + u64 + u8 + uint + vec + warn + + + + BBLMLanguageCode + Rust + BBLMLanguageDisplayName + Rust + BBLMEntryPointName + rustMain + BBLMScansFunctions + + BBLMFunctionScannerDoesFoldsToo + + BBLMSuffixMap + + + BBLMLanguageSuffix + .rs + + + BBLMUseHTMLFileSearchRules + + BBLMSpellableRunKinds + + com.barebones.bblm.line-comment + com.barebones.bblm.block-comment + + BBLMNonSpellableRunKinds + + com.barebones.bblm.code + com.barebones.bblm.double-string + + + + + diff --git a/rust.mm b/rust.mm new file mode 100644 index 0000000..8e88047 --- /dev/null +++ b/rust.mm @@ -0,0 +1,614 @@ +#include +#include + +#include +#include + +#include "BBLMInterface.h" +#include "BBLMTextIterator.h" + +#define kMaxLineLength 256 + +static NSString* const identifierColour = @"me.bsago.bblm.rust.identifier"; +static NSString* const attributeColour = @"me.bsago.bblm.rust.attribute"; +static NSString* const lifetimeColour = @"me.bsago.bblm.rust.lifetime"; + +static bool addRun(NSString *kind, int start,int len , const BBLMCallbackBlock& bblm_callbacks) +{ + if (len > 0) + { + return bblmAddRun(&bblm_callbacks, 'Rust', kind, start, len, false); + } + else + { + return true; + } +} + +SInt32 skipString(BBLMTextIterator &iter) +{ + SInt32 length = 1; + UniChar terminator = iter.GetNextChar(); + UniChar ch; + + while ((ch = iter.GetNextChar())) + { + length++; + if (ch == terminator) + { + break; + } + + if (ch == '\\') + { + iter++; + length++; + } + } + + return length; +} + +SInt32 skipLineComment(BBLMTextIterator &iter) +{ + SInt32 length = 2; + UniChar ch; + + iter += 2; + while ((ch = iter.GetNextChar())) + { + if (ch == '\n' || ch == '\r') + { + iter--; + break; + } + else + { + length++; + } + } + + return length; +} + +SInt32 skipBlockComment(BBLMTextIterator &iter) +{ + SInt32 length = 2; + iter += 2; + + while (iter.strcmp("*/", 2) != 0) + { + iter++; + length++; + } + + iter += 2; + length += 2; + + return length; +} + +SInt32 skipWhitespace(BBLMTextIterator &iter) +{ + SInt32 length = 0; + UniChar ch; + + while ((ch = iter.GetNextChar())) + { + if (isspace(ch)) + { + length++; + } + else + { + iter--; + break; + } + } + + return length; +} + +SInt32 skipWord(BBLMTextIterator &iter) +{ + SInt32 length = 0; + UniChar ch; + + while ((ch = iter.GetNextChar())) + { + if (isalpha(ch) || ch == '_') + { + length++; + } + else + { + iter--; + break; + } + } + + return length; +} + +SInt32 skipAttribute(BBLMTextIterator &iter) +{ + SInt32 length = 1; + UniChar ch; + + iter++; + while ((ch = iter.GetNextChar())) + { + if (ch == '\n' || ch == '\r') + { + break; + } + else + { + length++; + } + } + + return length; +} + +SInt32 skipNumber(BBLMTextIterator &iter) +{ + UInt32 length = 0; + UniChar ch; + bool hasSuffix = false; + + while ((ch = iter.GetNextChar())) + { + if (isdigit(ch)) + { + length++; + } + else if (ch == 'f' || ch == 'u' || ch == 'i') + { + hasSuffix = true; + length++; + break; + } + else + { + iter--; + break; + } + } + + if (hasSuffix) + { + if (iter.strcmp("8", 1) == 0) + { + iter++; + length++; + } + else if (iter.strcmp("16", 2) == 0 || iter.strcmp("32", 2) == 0 || iter.strcmp("64", 2) == 0) + { + iter += 2; + length += 2; + } + } + + return length; +} + +SInt32 skipToEndOfFunction(BBLMTextIterator &iter) +{ + SInt32 length = 0; + UniChar ch; + int braceLevel = 0, parenLevel = 0, bracketLevel = 0; + + while ((ch = iter.GetNextChar())) + { + length++; + + switch (ch) { + case '/': + ch = iter.GetNextChar(); + if (ch == '/') + { + iter -= 2; + length += (skipLineComment(iter) - 1); + } + else if (ch == '*') + { + iter -= 2; + length += (skipBlockComment(iter) - 1); + } + else if (ch) + { + iter--; + } + break; + + case '{': + braceLevel++; + break; + + case '}': + braceLevel--; + if (braceLevel < 1) return length; + break; + + case '(': + parenLevel++; + break; + + case ')': + parenLevel--; + break; + + case '[': + bracketLevel++; + break; + + case ']': + bracketLevel--; + break; + } + } + + return length; +} + +SInt32 scanForSymbol(BBLMTextIterator &iter, + const char *keyword, + int typeIfSo, + int indentLevel, + BBLMParamBlock ¶ms, + const BBLMCallbackBlock *callbacks) +{ + SInt32 whitespaceLen, wordLen; + int keywordLen = strlen(keyword); + + if (iter.strcmp(keyword, keywordLen) == 0) + { + iter += keywordLen; + if ((whitespaceLen = skipWhitespace(iter))) + { + if ((wordLen = skipWord(iter))) + { + UInt32 funLen = skipToEndOfFunction(iter); + UInt32 tokenOffset, funIndex; + UInt32 nameLen; + BBLMProcInfo info; + + iter -= (wordLen + funLen); + nameLen = keywordLen + whitespaceLen + wordLen; + iter -= (keywordLen + whitespaceLen); + + bblmAddTokenToBuffer(callbacks, params.fFcnParams.fTokenBuffer, iter.Address(), + nameLen, &tokenOffset); + + iter += (nameLen - wordLen); + + iter -= (keywordLen + whitespaceLen); + info.fFirstChar = info.fFunctionStart = iter.Offset(); + info.fSelStart = iter.Offset() + keywordLen + whitespaceLen; + info.fSelEnd = info.fSelStart + wordLen; + info.fFunctionEnd = info.fSelEnd + funLen; + info.fIndentLevel = indentLevel; + info.fKind = typeIfSo; + info.fFlags = 0; + info.fNameStart = tokenOffset; + info.fNameLength = nameLen; + bblmAddFunctionToList(callbacks, params.fFcnParams.fFcnList, info, &funIndex); + + iter += (keywordLen + whitespaceLen); + return info.fFunctionEnd; + } + else + { + iter -= (whitespaceLen + keywordLen); + } + } + else + { + iter -= keywordLen; + } + } + + return 0; +} + +static OSErr scanForFunctions(BBLMParamBlock ¶ms, const BBLMCallbackBlock *callbacks) +{ + BBLMTextIterator iter(params); + UniChar ch; + std::stack indents; + SInt32 funEnd; + + while ((ch = iter.GetNextChar())) + { + while (!indents.empty() && iter.Offset() >= indents.top()) + { + indents.pop(); + } + + const char* symbolToScanFor = NULL; + int typeIfSo; + + switch (ch) + { + case '"': + iter--; + skipString(iter); + break; + + case '/': + ch = iter.GetNextChar(); + if (ch == '/') + { + iter -= 2; + skipLineComment(iter); + } + else if (ch == '*') + { + iter -= 2; + skipBlockComment(iter); + } + else if (ch) + { + iter--; + } + break; + + case 'e': + symbolToScanFor = "enum"; + typeIfSo = kBBLMFunctionMark; + break; + + case 'f': + symbolToScanFor = "fn"; + typeIfSo = kBBLMFunctionMark; + break; + + case 'i': + symbolToScanFor = "impl"; + typeIfSo = kBBLMTypedef; + break; + + case 'm': + symbolToScanFor = "mod"; + typeIfSo = kBBLMFunctionMark; + break; + + case 's': + symbolToScanFor = "struct"; + typeIfSo = kBBLMFunctionMark; + break; + + case 't': + symbolToScanFor = "trait"; + typeIfSo = kBBLMFunctionMark; + break; + } + + if (symbolToScanFor != NULL) + { + iter--; + if ((funEnd = scanForSymbol(iter, symbolToScanFor, typeIfSo, indents.size(), params, callbacks))) + { + indents.push(funEnd); + } + else + { + iter++; + } + } + } + + return noErr; +} + +bool makeCodeRun(BBLMTextIterator &iter, SInt32 start, const BBLMCallbackBlock &callbacks) +{ + SInt32 len = iter.Offset() - start; + if (len) + { + return addRun(kBBLMCodeRunKind, start, len, callbacks); + } + else + { + return true; + } +} + +OSErr calculateRuns(BBLMParamBlock ¶ms, const BBLMCallbackBlock *callbacks) +{ + // BBLMTextIterator iter(params, params.fCalcRunParams.fStartOffset); + BBLMTextIterator iter(params, 0); + SInt32 runStart = iter.Offset(); + SInt32 runLen; + + UniChar ch; + while ((ch = iter.GetNextChar())) + { + if (ch == '"') + { + iter--; + if (!makeCodeRun(iter, runStart, *callbacks)) return noErr; + runStart = iter.Offset(); + runLen = skipString(iter); + if (!addRun(kBBLMDoubleQuotedStringRunKind, runStart, runLen, *callbacks)) return noErr; + runStart = iter.Offset(); + } + + // Have to distinguish the following things: + // 'a' (character) + // '\a' (escaped character) + // 'a (lifetime) + else if (ch == '\'') + { + ch = iter.GetNextChar(); + if (ch == '\\') + { + ch = iter.GetNextChar(); + if (ch) + { + ch = iter.GetNextChar(); + if (ch == '\'') + { + iter -= 4; + if (!makeCodeRun(iter, runStart, *callbacks)) return noErr; + runStart = iter.Offset(); + runLen = 4; + iter += 4; + if (!addRun(kBBLMSingleQuotedStringRunKind, runStart, runLen, *callbacks)) return noErr; + runStart = iter.Offset(); + } + else if (ch) + { + iter--; + } + } + } + else if (ch) + { + ch = iter.GetNextChar(); + if (ch == '\'') + { + iter -= 3; + if (!makeCodeRun(iter, runStart, *callbacks)) return noErr; + runStart = iter.Offset(); + runLen = 3; + iter += 3; + if (!addRun(kBBLMSingleQuotedStringRunKind, runStart, runLen, *callbacks)) return noErr; + runStart = iter.Offset(); + } + else if (ch) + { + iter -= 3; + if (!makeCodeRun(iter, runStart, *callbacks)) return noErr; + runStart = iter.Offset(); + iter++; + runLen = 1 + skipWord(iter); + if (!addRun(lifetimeColour, runStart, runLen, *callbacks)) return noErr; + runStart = iter.Offset(); + } + } + } + + else if (ch == '/') + { + ch = iter.GetNextChar(); + if (ch == '/') + { + iter -= 2; + if (!makeCodeRun(iter, runStart, *callbacks)) return noErr; + runStart = iter.Offset(); + runLen = skipLineComment(iter); + if (!addRun(kBBLMLineCommentRunKind, runStart, runLen, *callbacks)) return noErr; + runStart = iter.Offset(); + } + else if (ch == '*') + { + iter -= 2; + if (!makeCodeRun(iter, runStart, *callbacks)) return noErr; + runStart = iter.Offset(); + runLen = skipBlockComment(iter); + if (!addRun(kBBLMBlockCommentRunKind, runStart, runLen, *callbacks)) return noErr; + runStart = iter.Offset(); + } + else if (ch) + { + iter--; + } + } + + else if (ch == '#') + { + iter--; + if (!makeCodeRun(iter, runStart, *callbacks)) return noErr; + runStart = iter.Offset(); + runLen = skipAttribute(iter); + if (!addRun(attributeColour, runStart, runLen, *callbacks)) return noErr; + runStart = iter.Offset(); + } + + else if (isupper(ch)) + { + iter--; + if (!makeCodeRun(iter, runStart, *callbacks)) return noErr; + runStart = iter.Offset(); + runLen = skipWord(iter); + if (!addRun(identifierColour, runStart, runLen, *callbacks)) return noErr; + runStart = iter.Offset(); + } + + else if (isdigit(ch)) + { + iter--; + if (!makeCodeRun(iter, runStart, *callbacks)) return noErr; + runStart = iter.Offset(); + runLen = skipNumber(iter); + if (!addRun(kBBLMNumberRunKind, runStart, runLen, *callbacks)) return noErr; + runStart = iter.Offset(); + } + } + + makeCodeRun(iter, runStart, *callbacks); + return noErr; +} + +OSErr adjustRange(BBLMParamBlock ¶ms, const BBLMCallbackBlock &callbacks) +{ + return noErr; +} + +OSErr guessLanguage(BBLMParamBlock ¶ms) +{ + BBLMTextIterator iter(params); + + if (iter.strcmp("use ", 4) == 0 || iter.strcmp("#![crate_id", 11) == 0) + { + params.fGuessLanguageParams.fGuessResult = kBBLMGuessDefiniteYes; + } + + return noErr; +} + +#pragma mark - + +extern "C" +{ + OSErr rustMain(BBLMParamBlock ¶ms, const BBLMCallbackBlock &bblmCallbacks); + OSErr rustMain(BBLMParamBlock ¶ms, const BBLMCallbackBlock &bblmCallbacks) + { + // Dispatch message. + OSErr result = noErr; + + switch (params.fMessage) + { + case kBBLMDisposeMessage: + case kBBLMSetCategoriesMessage: + // Message understood, but no action required. + break; + + case kBBLMInitMessage: + break; + + case kBBLMScanForFunctionsMessage: + result = scanForFunctions(params, &bblmCallbacks); + break; + + case kBBLMCalculateRunsMessage: + result = calculateRuns(params, &bblmCallbacks); + break; + + case kBBLMGuessLanguageMessage: + result = guessLanguage(params); + break; + + case kBBLMAdjustRangeMessage: + result = adjustRange(params, bblmCallbacks); + break; + + default: + result = paramErr; + } + + return result; + } +} \ No newline at end of file