public CodeSegment() { _codesegment = new SimpleSegment(); _type = Token.Unknown; _line = -1; _next = null; _previous = null; }
public CodeSegment(ProjectItemCodeDocument codeDocument, Token token, string tokenstr, SimpleSegment anchorsegment, int line, int colstart, CodeSegment previous) { _type = token; _tokenstring = tokenstr; _codesegment = anchorsegment; _line = line; _column = colstart; _previous = previous; _codeDocument = codeDocument; }
public void Parse(CodeSegment start) { // init _current = start; _operands.Clear(); _operators.Clear(); _operators.Push(Sentinel); while(true) { _operands.Push(_current); } }
public InvokeCompletionViewModel(CodeFileViewModel documentVM, CodeSegment methodSegment, int startParam) { _document = documentVM.CodeDocument; _documentVM = documentVM; _toolTip = new ToolTip(); _toolTip.Placement = PlacementMode.Custom; _toolTip.PlacementTarget = _documentVM.Editor.TextArea.TextView; _toolTip.Content = this; _toolTip.CustomPopupPlacementCallback = PopupPlacement; _documentVM.Editor.TextArea.KeyDown += (s, e) => { if(e.Key == Key.Escape) this.CloseCommand.Execute(null); }; //_documentVM.Editor.TextArea.TextEntered += OnTextEntered; _documentVM.Editor.TextArea.Caret.PositionChanged += OnCaretPositionChanged; AllParameters = new ObservableCollection<InvokeParameter>(); SetMethod(methodSegment); SetCurrentParam(startParam); }
async void HandleCompletionEvent(char currentChar, CodeSegment segment, TextCompositionEventArgs e) { if(e.Text.Length == 1 && !omitCodeCompletion.Contains(currentChar)) { // this is just for first debugging purposes // as this code belongs to a completion service which handles and caches those completion items // Open code completion after the user has pressed dot: if(e.Text == ".") { //ensure we have a updated tokenizer _projectitem.EnsureTokenizerHasWorked(); await _projectitem.AST.CompileTokenFileAsync(); Application.Current.Dispatcher.Invoke(new Action(() => { IList<ICompletionData> data = CreateNewCompletionWindow().CompletionList.CompletionData; // do type lookup & list avaiable members var ctx = _projectitem.AST.GetCodeContext(_texteditor.CaretOffset - 1, true); if(ctx != null && ctx.Segment != null) { if(ctx.Segment.CodeDOMObject is CodeThisReferenceExpression) { foreach(var m in ctx.EnclosingType.GetInheritedMembers()) { data.Add(CompletionItem.Build(m)); } } else if(ctx.Segment.CodeDOMObject is CodeBaseReferenceExpression) { foreach(CodeTypeReferenceEx basetype in ctx.EnclosingType.BaseTypes) { var td = basetype.ResolveTypeDeclarationCache(); if(td != null) { foreach(var m in td.GetInheritedMembers()) data.Add(CompletionItem.Build(m)); } } } } if(data.Any()) { _completionWindow.StartOffset++; _completionWindow.Show(); } })); } else if(_completionWindow == null && e.Text != "\n" && ((AsciiHelper.IsAsciiLiteralLetter(currentChar) || allowedspecailChars.Contains(currentChar)) && !AsciiHelper.IsAsciiNum(currentChar))) { // && !whitespaces.Contains(carretChar) // show avaiable global Methods & build in Methods + commands if(segment == null) { return; } else { if(segment.Token == Token.MultiLineComment || segment.Token == Token.SingleLineComment) return; } Application.Current.Dispatcher.Invoke(new Action(() => { IList<ICompletionData> data = CreateNewCompletionWindow().CompletionList.CompletionData; foreach(var item in GetStaticCompletionItems()) { data.Add(item); } CodeContext ctx; if(_texteditor.Document.TextLength > _texteditor.CaretOffset) { ctx = _projectitem.AST.GetCodeContext(_texteditor.CaretOffset, true); } else { // get root type context ctx = new CodeContext(_projectitem.AST); ctx.EnclosingType = _projectitem.AST.GetRootTypeSnapshot(); } foreach(var m in ctx.GetVisibleMembers()) { data.Add(CompletionItem.Build(m)); } //_completionWindow.StartOffset++; _completionWindow.Show(); })); } } else if(whitespaces.Contains(currentChar)) { if(segment != null) { var s = segment.ThisOrPreviousOmit(TokenHelper.WhiteSpacesNewLine); Application.Current.Dispatcher.Invoke(new Action(() => { if(s != null && s.Token == Token.KeyWord && (s.TokenString.Equals("new", StringComparison.CurrentCultureIgnoreCase) || s.TokenString.Equals("extends", StringComparison.CurrentCultureIgnoreCase))) { var ctx = _projectitem.AST.GetCodeContext(_texteditor.CaretOffset); IList<ICompletionData> data = CreateNewCompletionWindow().CompletionList.CompletionData; bool any = false; foreach(var m in ctx.GetVisibleMembers()) { if(m is CodeTypeDeclaration) { data.Add(CompletionItem.Build(m)); any = true; } } if(any) { _completionWindow.StartOffset++; _completionWindow.Show(); } } })); } } }
ProjectItemCodeDocument ParseIncludeDirective(CodeSegment includeDirective, ProjectItemCodeDocument document) { ThrowUtil.ThrowIfNull(includeDirective); ThrowUtil.ThrowIfNull(document); SmartCodeProjectAHK project = document.Project as SmartCodeProjectAHK; if(project == null) throw new NotSupportedException("Expected an instance of SmartCodeProjectAHK!"); if(_project.StartUpCodeDocument == null) return null; var libRegEx = new Regex(@"<(.*?)>"); // parse include directive var next = includeDirective.NextOmit(TokenHelper.WhiteSpaces); if(next != null) { int len = next.TokenString.Length; if(len > 0) { if(libRegEx.IsMatch(next.TokenString)) { string docName = libRegEx.Match(next.TokenString).Groups[1].Value; // seach local library files var doc = project.LocalLib.FindAllItems<ProjectItemCodeDocument>().ToList() .Find(x => Path.GetFileNameWithoutExtension(x.FilePath).Equals(docName, StringComparison.InvariantCultureIgnoreCase)); if(doc == null && project.StdLib != null) { // seach in standard library files doc = project.StdLib.FindAllItems<ProjectItemCodeDocument>().ToList() .Find(x => x.FilePath != null && Path.GetFileNameWithoutExtension(x.FilePath).Equals(docName, StringComparison.InvariantCultureIgnoreCase)); } if(doc != null) { var directive = new IncludeDirective() { ResolvedFilePath = doc.FilePath, ResolvedCodeDocument = doc }; next.CodeDOMObject = directive; } else { next.ErrorContext = new CodeError() { Description = string.Format("File not found!") }; } return doc; } else { // parse direct/relative path var directive = ParseIncludePath(document, next); var includeFilePath = directive.ResolvedFilePath; var doc = project.CodeDocuments.ToList() .Find(x => x.FilePath.Equals(includeFilePath, StringComparison.InvariantCultureIgnoreCase)); directive.ResolvedCodeDocument = doc; return doc; } } } return null; }
IncludeDirective ParseIncludePath(ProjectItemCodeDocument codeDoc, CodeSegment segment) { string workingDir = Path.GetDirectoryName(_project.StartUpCodeDocument.FilePath); StringBuilder sb = new StringBuilder(); CodeSegment next = segment; CodeSegment current = null; List<CodeSegment> _pathTokens = new List<CodeSegment>(); while(next != null && next.Token != Token.NewLine) { current = next; next = next.Next; if(current.Token == Token.TraditionalString) sb.Append(current.TokenString); else if(current.Token == Token.Deref) { if(current.Next != null && current.Next.Token == Token.Identifier) { if(current.Next.TokenString.Equals(WORKINGDIR_VAR, StringComparison.InvariantCultureIgnoreCase)) { sb.Append(workingDir); } else { RegisterError(codeDoc, current.Next, "Unknown precompiler Variable!"); } if(current.Next != null && current.Next.Next != null) next = current.Next.Next.Next; } else if(current.Next != null) { RegisterError(codeDoc, current.Next, "Expected Identifier after Deref!"); } } if(current != null) _pathTokens.Add(current); } var path = sb.ToString(); try { if(!path.Contains(':')) { path = Path.Combine(workingDir, path); } } catch { path = ""; } var directive = new IncludeDirective() { ResolvedFilePath = path }; CodeError fail = null; if(!File.Exists(path)){ var err = string.Format("File not found!\n" + path); fail = new CodeError() { Description = err }; if(_pathTokens.Any()) RegisterError(codeDoc, _pathTokens.First(), err); } foreach(var s in _pathTokens) { s.CodeDOMObject = directive; if(fail != null) { s.ErrorContext = fail; } } return directive; }
CodeExpression ParseExpression(CodeSegment tokenSegment, out CodeSegment nextToParse, CodeTypeDeclarationEx enclosingType) { CodeExpression expression = null; nextToParse = tokenSegment.Next; if(tokenSegment.Token == Token.Identifier && tokenSegment.Next != null && tokenSegment.Next.Token == Token.LiteralBracketOpen) { bool ismethodDeclaration = false; var closingliteral = tokenSegment.Next.FindClosingBracked(true); if(closingliteral != null) { //ensure that it is not a defect method declaration var bra = closingliteral.NextOmit(whitespacetokenNewLines); if(bra != null && bra.Token == Token.BlockOpen) { // it is a method indeed ismethodDeclaration = true; } } else { RegisterError(_document, tokenSegment.Next, "Missing: )"); } #region Parse for Method Invokes if(!ismethodDeclaration) { CodeTypeDeclarationEx methodContext = null; if(tokenSegment.Previous != null && tokenSegment.Previous.Previous != null && tokenSegment.Previous.Token == Token.MemberInvoke) { var invoker = tokenSegment.Previous.Previous; #region adjust Method Context if(_document.CodeLanguage.SELFREF_CAN_BE_OMITTED) methodContext = enclosingType; if(invoker.CodeDOMObject is CodeBaseReferenceExpression) { foreach(CodeTypeReferenceEx bt in enclosingType.BaseTypes) { var typedeclaration = bt.ResolveTypeDeclarationCache(); if(typedeclaration != null && typedeclaration.IsClass) { methodContext = typedeclaration; break; } } } else if(invoker.CodeDOMObject is CodeThisReferenceExpression) { methodContext = enclosingType; } else if(invoker.Token == Token.Identifier) { invoker.CodeDOMObject = CodeTypeDeclarationDynamic.Default; methodContext = CodeTypeDeclarationDynamic.Default; } #endregion } var invokeExpression = new CodeMethodInvokeExpression(); var methodRef = new CodeMethodReferenceExpressionExAHK(_document, null, tokenSegment.TokenString, methodContext); invokeExpression.Method = methodRef; tokenSegment.CodeDOMObject = methodRef; expression = invokeExpression; } nextToParse = tokenSegment.Next.Next; #endregion } else if(tokenSegment.Token == Token.KeyWord) { #region Parse Keywords if(tokenSegment.TokenString.Equals("new", _document.CodeLanguage.NameComparisation)) { #region NEW parse for new Object Expressions var newObjectInvoke = tokenSegment.NextOmit(whitespacetokenNewLines); if(newObjectInvoke != null && newObjectInvoke.Token == Token.Identifier) { var objectinstangicing = new CodeObjectCreateExpression(); objectinstangicing.CreateType = new CodeTypeReferenceEx(_document, newObjectInvoke.TokenString, enclosingType); tokenSegment.CodeDOMObject = objectinstangicing; newObjectInvoke.CodeDOMObject = objectinstangicing.CreateType; expression = objectinstangicing; nextToParse = newObjectInvoke.Next; } #endregion } else if(tokenSegment.TokenString.Equals("this", _document.CodeLanguage.NameComparisation)) { var thisrefExpression = new CodeThisReferenceExpression(); tokenSegment.CodeDOMObject = thisrefExpression; expression = thisrefExpression; } else if(tokenSegment.TokenString.Equals("base", _document.CodeLanguage.NameComparisation)) { var baserefExpression = new CodeBaseReferenceExpression(); tokenSegment.CodeDOMObject = baserefExpression; expression = baserefExpression; } #endregion } else if(tokenSegment.Token == Token.Identifier && tokenSegment.Previous != null && tokenSegment.Previous.Token == Token.MemberInvoke) { #region Parse MemberInvoke (Dot) Class.Member var context = tokenSegment.Previous.Previous; if(context == null) { //unexpected! var err = "Unexpected Member Invoke!"; RegisterError(_document, tokenSegment, err); RegisterError(_document, tokenSegment.Previous, err); nextToParse = tokenSegment.Next; } else if(context.Token == Token.KeyWord && context.TokenString.Equals("this", _document.CodeLanguage.NameComparisation)) { var propRef = new CodePropertyReferenceExpressionEx(_document, null, tokenSegment.TokenString, enclosingType); tokenSegment.CodeDOMObject = propRef; } else if(context.Token == Token.KeyWord && context.TokenString.Equals("base", _document.CodeLanguage.NameComparisation)) { CodeTypeDeclarationEx typedeclaration = null; foreach(CodeTypeReferenceEx bt in enclosingType.BaseTypes) { typedeclaration = bt.ResolveTypeDeclarationCache(); if(typedeclaration != null && typedeclaration.IsClass) { break; } } var propRef = new CodePropertyReferenceExpressionEx(_document, null, tokenSegment.TokenString, typedeclaration); tokenSegment.CodeDOMObject = propRef; } else if(context.Token == Token.Identifier) { // we currently not supprt real expression parsing, so leave here... context.CodeDOMObject = CodeTypeDeclarationDynamic.Default; var propRef = new CodePropertyReferenceExpressionEx(_document, null, tokenSegment.TokenString, CodeTypeDeclarationDynamic.Default); tokenSegment.CodeDOMObject = propRef; } #region Parse for one hirarchy this/base Property/Field Invokes #endregion #endregion } else if(tokenSegment.Token == Token.TraditionalCommandInvoke) { #region Parse Traditional Command Invoke var members = from m in _languageRoot.Members.Cast<CodeTypeMember>() let methd = m as CodeMemberMethodExAHK where methd != null && methd.IsTraditionalCommand && methd.Name.Equals(tokenSegment.TokenString, StringComparison.InvariantCultureIgnoreCase) select methd; if(members.Any()) { var invokeExpression = new CodeMethodInvokeExpression(); var methodRef = new CodeMethodReferenceExpressionExAHK(_document, members.First()); tokenSegment.CodeDOMObject = methodRef; expression = invokeExpression; } else { RegisterError(_document, tokenSegment, string.Format("Unknown traditional Command '{0}'", tokenSegment.TokenString)); } #endregion } else if(tokenSegment.Token == Token.LiteralString) { if(tokenSegment.TokenString[tokenSegment.TokenString.Length - 1] != '"') { RegisterError(_document, tokenSegment, "Missing string end Quote"); } } if(!(nextToParse != null && nextToParse.LineNumber == tokenSegment.LineNumber)) { nextToParse = null; } return expression; }
CodeLinePragma CreatePragma(CodeSegment segment, string filename) { return new CodeLinePragma() { LineNumber = segment.LineNumber, FileName = filename }; }
void RegisterError(Projecting.ProjectItemCodeDocument codeitem, CodeSegment segment, string errorDescription) { ThrowUtil.ThrowIfNull(codeitem); ThrowUtil.ThrowIfNull(segment); var errorService = codeitem.Project.Solution.ErrorService; segment.ErrorContext = new CodeError() { Description = errorDescription }; errorService.Add(new Errors.ErrorItem(segment, codeitem)); }
CodeCommentStatement ExtractComment(CodeSegment identifier) { var comment = identifier.PreviousOmit(whitespacetokenNewLines); if(comment != null && comment.Token == Token.MultiLineComment) { return new CodeCommentStatement(GetDocumentationComment(comment.TokenString), true); } else if(comment != null && comment.Token == Token.SingleLineComment) { //todo: collect all above singleline comments } return null; }
void EndActiveToken(int index) { int tokenRangeLenght = index - _currentRangeStart; if(tokenRangeLenght > 0) { var str = _text.Substring(_currentRangeStart, tokenRangeLenght).Trim(trimchars); if(!(_activeToken == Token.Unknown && str.Length == 0)) { Token? tokenToStore = null; if(_activeToken == Token.Unknown) { if(IsNumber(str)) { _activeToken = Token.Number; } else if(IsHexNumber(str)) { _activeToken = Token.HexNumber; } else if(KEYWORDS.Contains(str.ToLowerInvariant())) { _activeToken = Token.KeyWord; } else { tokenToStore = Token.Identifier; } } if(_activeToken == Token.OperatorFlow) { tokenToStore = OPERATOR_TOKEN.FindOperatorToken(str); } if(tokenRangeLenght > 1 && _currentToken == Token.NewLine) tokenRangeLenght--; int linenumber = _currentLine; if(_activeToken == Token.NewLine) --linenumber; if((_activeToken == Token.TraditionalCommandInvoke || _activeToken == Token.TraditionalAssign || _activeToken == Token.Directive) && _currentToken != Token.NewLine) _traditionalMode = true; var currentsegment = new CodeSegment(_codeitem, tokenToStore.HasValue ? tokenToStore.Value : _activeToken, str, new SimpleSegment(_currentRangeStart, tokenRangeLenght), linenumber, _currentColStart, _previous); if(_previous != null) _previous.Next = currentsegment; _previous = currentsegment; _codesegmentsWorker.Add(currentsegment); if(currentsegment.Token == Token.Directive) _directivesWorker.Add(currentsegment); } } _currentRangeStart = index; _currentColStart = _currentColumn; }
/// <summary> /// Very handy Method to find the Open Bracket Codesegment of this Close Braket Segment /// </summary> /// <param name="allowNewlinesbetween">Should the search go over newlines</param> /// <returns>The cloasing codesegment or NULL if nothing was found</returns> public CodeSegment FindOpenBracked(bool allowNewlinesbetween) { if(!TokenHelper.IsClosedBracketToken(this.Token)) throw new NotSupportedException("Must be called on closed barcket type"); if(_openSegment == null) { int openBracketCounter = 1; CodeSegment current; CodeSegment previous = this; Token closingbracket = this.Token; Token openbracket = TokenHelper.GetOpenToken(this.Token); while((current = previous.Previous) != null) { if(current.Token == Token.NewLine && !allowNewlinesbetween) break; else if(current.Token == closingbracket) openBracketCounter++; else if(current.Token == openbracket) { openBracketCounter--; if(openBracketCounter == 0) { _openSegment = current; break; } } previous = current; } } return _openSegment; }
void SetMethod(CodeSegment methodSegment) { _methodRef = methodSegment.CodeDOMObject as CodeMethodReferenceExpressionEx; var methodDecl = _methodRef.ResolvedMethodMember; Prefix = methodDecl.Name + "("; Sufix = ")"; InvokeDescription = _methodRef.CommentInfo; _documentVM.Editor.TextArea.TextView.EnsureVisualLines(); var geometrys = BackgroundGeometryBuilder.GetRectsForSegment(_documentVM.Editor.TextArea.TextView, methodSegment.Range); if(geometrys.Any()){ popuplacement = geometrys.First().BottomLeft; //_toolTip.VerticalOffset = pos.Y; //_toolTip.HorizontalOffset = pos.X; } AllParameters.Clear(); int i = 0; foreach(CodeParameterDeclarationExpressionEx p in methodDecl.Parameters) { string typeprefix = ""; if(p.Type != null) { typeprefix = p.Type.BaseType + " "; } var pVM = new InvokeParameter(((p.Direction == FieldDirection.Ref) ? "byref " : "") + typeprefix + p.Name + ((++i != methodDecl.Parameters.Count) ? ", " : ""), "-") { ParameterDescripton = p.ParameterDocumentationComment }; AllParameters.Add(pVM); } }
/// <summary> /// Searches the enclosing Methode-Invoke Expression /// </summary> /// <param name="segment">segment to analyze</param> /// <returns>Returns the enclosing Method Reference Expression Segment</returns> public static CodeSegment FindEnclosingMethodInvoke(CodeSegment segment, out int paramNumber) { int literalBracketCnt = 1; int indexerBrackedCnt = 0; paramNumber = 1; //CodeMethodReferenceExpressionEx methodRef = null; CodeSegment current = segment; while(current != null) { if(_endingTokens.Contains(current.Token)) break; else if(current.Token == Token.LiteralBracketClosed) literalBracketCnt++; else if(current.Token == Token.IndexerBracketClosed) literalBracketCnt++; else if(current.Token == Token.IndexerBracketOpen) literalBracketCnt--; else if(current.Token == Token.LiteralBracketOpen) { literalBracketCnt--; } else if(current.Token == Token.ParameterDelemiter) { if(literalBracketCnt == 1 && indexerBrackedCnt == 0) { paramNumber++; } } else if(current.Token == Token.Identifier && current.CodeDOMObject is CodeMethodReferenceExpressionEx) { if(literalBracketCnt == 0 && indexerBrackedCnt == 0) { //methodRef = current.CodeDOMObject as CodeMethodReferenceExpressionEx; return current; //break; } } current = current.Previous; } return null; //methodRef; }
public void Add(CodeSegment s) { CodeSegments.Add(s); }
public CodeTokenLine(CodeSegment initialToken) : this() { Line = initialToken.LineNumber; CodeSegments = new List<CodeSegment>() { initialToken }; }
void Consume() { _current = _current.Next; }
protected void RegisterError(Projecting.ProjectItemCodeDocument codeitem, CodeSegment segment, string errorDescription) { var errorService = codeitem.Project.Solution.ErrorService; var err = new CodeError() { Description = errorDescription }; if(segment != null) { segment.ErrorContext = err; errorService.Add(new Errors.ErrorItem(segment, codeitem, ErrorSource.DirectiveParser)); } else { errorService.Add(new Errors.ErrorItem(err, codeitem, ErrorSource.DirectiveParser)); } }