Index: configure.in =================================================================== --- configure.in (revision 2465) +++ configure.in (working copy) @@ -113,6 +113,16 @@ enable_java=no) AM_CONDITIONAL(ENABLE_JAVA, test x$enable_java = xyes) +BOO_REQUIRED_VERSION=0.5.2.99 +AC_ARG_ENABLE(boo, + AC_HELP_STRING([--enable-boo], + [enable support for boo [default=no]]), + [PKG_CHECK_MODULES(BOO, boo >= $BOO_REQUIRED_VERSION, enable_boo=yes, enable_boo=no)], + enable_boo=no) + +AM_CONDITIONAL(ENABLE_BOO, test x$enable_boo = xyes) +AC_SUBST(BOO_LIBS) + MOZILLA_HOME="`$PKG_CONFIG --variable=libdir mozilla-gtkmozembed`" AC_SUBST(MOZILLA_HOME) @@ -216,6 +226,7 @@ Extras/MonoQuery/MonoQuery.addin.xml Extras/MonoDeveloperExtensions/Makefile Extras/JavaBinding/Makefile +Extras/BooBinding/Makefile contrib/Makefile ]) @@ -231,4 +242,5 @@ echo " * MySQL: yes" echo " * SQLite: $enable_monoquery_sqlite" echo " * java support: $enable_java" +echo " * boo support: $enable_boo" echo "" Index: build/data/resources/icons/Makefile.am =================================================================== --- build/data/resources/icons/Makefile.am (revision 2464) +++ build/data/resources/icons/Makefile.am (working copy) @@ -2,7 +2,14 @@ monodevelopdir = $(libdir)/monodevelop iconsdir = $(monodevelopdir)/data/resources/icons -icons_DATA = C\#.File.EmptyFile \ +icons_DATA = BooBinding.Base \ +Boo.File.EmptyFile \ +Boo.File.Form \ +Boo.FileIcon \ +Boo.Project.EmptyProject \ +Boo.Project.Form \ +Boo.ProjectIcon \ +C\#.File.EmptyFile \ C++.File.EmptyFile \ C\#.File.Form \ C++.File.Form \ Index: Extras/Makefile.am =================================================================== --- Extras/Makefile.am (revision 2464) +++ Extras/Makefile.am (working copy) @@ -1,3 +1,3 @@ #SUBDIRS = PythonBinding MonoQuery -SUBDIRS = MonoQuery MonoDeveloperExtensions JavaBinding +SUBDIRS = MonoQuery MonoDeveloperExtensions JavaBinding BooBinding Index: Extras/BooBinding/BooAmbience.boo =================================================================== --- Extras/BooBinding/BooAmbience.boo (revision 0) +++ Extras/BooBinding/BooAmbience.boo (revision 0) @@ -0,0 +1,478 @@ +#region license +// Copyright (c) 2004, Daniel Grunwald (daniel@danielgrunwald.de) +// All rights reserved. +// +// BooBinding is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// BooBinding is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with BooBinding; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#endregion + +namespace BooBinding + +import System +import System.Collections +import System.Text +import MonoDevelop.Internal.Parser +import MonoDevelop.Services +import MonoDevelop.Core.Properties + +class BooAmbience(AbstractAmbience): + [Getter(TypeConversionTable)] + static _typeConversionTable = { + 'System.Void' : 'void', + 'System.Object' : 'object', + 'System.Boolean' : 'bool', + 'System.Byte' : 'byte', + 'System.SByte' : 'sbyte', + //'System.Char' : 'char', + //'System.Enum' : 'enum', + 'System.Int16' : 'short', + 'System.Int32' : 'int', + 'System.Int64' : 'long', + 'System.UInt16' : 'ushort', + 'System.UInt32' : 'uint', + 'System.UInt64' : 'ulong', + 'System.Single' : 'single', + 'System.Double' : 'double', + 'System.Decimal' : 'decimal', + 'System.String' : 'string', + 'System.DateTime' : 'date', + 'System.TimeSpan' : 'timespan', + 'System.Type' : 'type', + 'System.Array' : 'array', + 'System.Text.RegularExpressions.Regex' : 'regex' + } + + static _reverseTypeConversionTable as Hashtable + + static ReverseTypeConversionTable: + get: + if _reverseTypeConversionTable == null: + _reverseTypeConversionTable = Hashtable() + for e as DictionaryEntry in _typeConversionTable: + _reverseTypeConversionTable.Add(e.Value, e.Key) + return _reverseTypeConversionTable + + + private def ModifierIsSet(modifier as ModifierEnum, query as ModifierEnum) as bool: + return (modifier & query) == query + + override def Convert(modifier as ModifierEnum) as string: + if ShowAccessibility: + if ModifierIsSet(modifier, ModifierEnum.Public): + return 'public ' + elif ModifierIsSet(modifier, ModifierEnum.Private): + return 'private ' + elif ModifierIsSet(modifier, ModifierEnum.ProtectedAndInternal): + return 'protected internal ' + elif ModifierIsSet(modifier, ModifierEnum.ProtectedOrInternal): + return 'internal protected ' + elif ModifierIsSet(modifier, ModifierEnum.Internal): + return 'internal ' + elif ModifierIsSet(modifier, ModifierEnum.Protected): + return 'protected ' + return '' + + private def GetModifier(decoration as IDecoration) as string: + ret as string = '' + if IncludeHTMLMarkup: + ret += '' + + if decoration.IsStatic: + ret += 'static ' + elif decoration.IsFinal: + ret += 'final ' + elif decoration.IsVirtual: + ret += 'virtual ' + elif decoration.IsOverride: + ret += 'override ' + elif decoration.IsNew: + ret += 'new ' + + if IncludeHTMLMarkup: + ret += '' + + return ret + + override def Convert(c as IClass) as string: + builder as StringBuilder = StringBuilder() + builder.Append(Convert(c.Modifiers)) + if IncludeHTMLMarkup: + builder.Append('') + + cType = c.ClassType + + if ShowModifiers: + if c.IsSealed: + if cType == ClassType.Delegate or cType == ClassType.Enum: + pass + else: + builder.Append('final ') + elif c.IsAbstract and cType != ClassType.Interface: + builder.Append('abstract ') + + if IncludeHTMLMarkup: + builder.Append('') + + if ShowModifiers: + if cType == ClassType.Delegate: + builder.Append('callable ') + elif cType == ClassType.Class: + builder.Append('class ') + elif cType == ClassType.Struct: + builder.Append('struct ') + elif cType == ClassType.Interface: + builder.Append('interface ') + elif cType == ClassType.Enum: + builder.Append('enum ') + + if cType == ClassType.Delegate and c.Methods.Count > 0: + for m as IMethod in c.Methods: + if m.Name == 'Invoke': + builder.Append(Convert(m.ReturnType)) + builder.Append(' ') + + if IncludeHTMLMarkup: + builder.Append('') + + if UseFullyQualifiedMemberNames: + builder.Append(c.FullyQualifiedName) + else: + builder.Append(c.Name) + + if IncludeHTMLMarkup: + builder.Append('') + + if c.ClassType == ClassType.Delegate: + builder.Append(' (') + if IncludeHTMLMarkup: + builder.Append('
') + + for m as IMethod in c.Methods: + if m.Name == 'Invoke': + for i in range(m.Parameters.Count): + if IncludeHTMLMarkup: + builder.Append('   ') + + builder.Append(Convert(m.Parameters[i])) + if i + 1 < m.Parameters.Count: + builder.Append(', ') + + if IncludeHTMLMarkup: + builder.Append('
') + + builder.Append(Char.Parse(')')) + elif ShowInheritanceList: + if c.BaseTypes.Count > 0: + builder.Append('(') + for i in range(c.BaseTypes.Count): + builder.Append(c.BaseTypes[i]) + if i + 1 < c.BaseTypes.Count: + builder.Append(', ') + builder.Append(')') + + if IncludeBodies: + builder.Append(':\n') + + return builder.ToString() + + override def ConvertEnd(c as IClass) as string: + return '' + + override def Convert(field as IField) as string: + builder as StringBuilder = StringBuilder() + builder.Append(Convert(field.Modifiers)) + if IncludeHTMLMarkup: + builder.Append('') + + if ShowModifiers: + if field.IsStatic and field.IsLiteral: + builder.Append('const ') + elif field.IsStatic: + builder.Append('static ') + + if field.IsReadonly: + builder.Append('readonly ') + + + if IncludeHTMLMarkup: + builder.Append('') + + if IncludeHTMLMarkup: + builder.Append('') + + if UseFullyQualifiedMemberNames: + builder.Append(field.FullyQualifiedName) + else: + builder.Append(field.Name) + + if field.ReturnType != null: + builder.Append(' as ') + builder.Append(Convert(field.ReturnType)) + + if IncludeHTMLMarkup: + builder.Append('') + + return builder.ToString() + + override def Convert(property as IProperty) as string: + builder as StringBuilder = StringBuilder() + builder.Append(Convert(property.Modifiers)) + if ShowModifiers: + builder.Append(GetModifier(property)) + + if IncludeHTMLMarkup: + builder.Append('') + + if UseFullyQualifiedMemberNames: + builder.Append(property.FullyQualifiedName) + else: + builder.Append(property.Name) + + if IncludeHTMLMarkup: + builder.Append('') + + if property.Parameters.Count > 0: + builder.Append('(') + if IncludeHTMLMarkup: + builder.Append('
') + + for i in range(property.Parameters.Count): + if IncludeHTMLMarkup: + builder.Append('   ') + + builder.Append(Convert(property.Parameters[i])) + if i + 1 < property.Parameters.Count: + builder.Append(', ') + + if IncludeHTMLMarkup: + builder.Append('
') + + builder.Append(')') + + if property.ReturnType != null: + builder.Append(' as ') + builder.Append(Convert(property.ReturnType)) + + if IncludeBodies: + builder.Append(': ') + if property.CanGet: + builder.Append('get ') + + if property.CanSet: + builder.Append('set ') + + return builder.ToString() + + override def Convert(e as IEvent) as string: + builder as StringBuilder = StringBuilder() + builder.Append(Convert(e.Modifiers)) + if ShowModifiers: + builder.Append(GetModifier(e)) + + if IncludeHTMLMarkup: + builder.Append('') + + if UseFullyQualifiedMemberNames: + builder.Append(e.FullyQualifiedName) + else: + builder.Append(e.Name) + + if IncludeHTMLMarkup: + builder.Append('') + + if e.ReturnType != null: + builder.Append(' as ') + builder.Append(Convert(e.ReturnType)) + + return builder.ToString() + + override def Convert(m as IIndexer) as string: + builder as StringBuilder = StringBuilder() + builder.Append(Convert(m.Modifiers)) + if IncludeHTMLMarkup: + builder.Append('') + + if ShowModifiers and m.IsStatic: + builder.Append('static ') + + if IncludeHTMLMarkup: + builder.Append('') + + if m.ReturnType != null: + builder.Append(Convert(m.ReturnType)) + builder.Append(' ') + + if IncludeHTMLMarkup: + builder.Append('') + + if UseFullyQualifiedMemberNames: + builder.Append(m.FullyQualifiedName) + else: + builder.Append(m.Name) + + if IncludeHTMLMarkup: + builder.Append('') + + builder.Append('Indexer(') + if IncludeHTMLMarkup: + builder.Append('
') + + for i in range(m.Parameters.Count): + if IncludeHTMLMarkup: + builder.Append('   ') + + builder.Append(Convert(m.Parameters[i])) + if i + 1 < m.Parameters.Count: + builder.Append(', ') + + if IncludeHTMLMarkup: + builder.Append('
') + + builder.Append(')') + + return builder.ToString() + + override def Convert(m as IMethod) as string: + builder as StringBuilder = StringBuilder() + builder.Append(Convert(m.Modifiers)) + if ShowModifiers: + builder.Append(GetModifier(m)) + + //builder.Append('def ') if ShowReturnType + + if IncludeHTMLMarkup: + builder.Append('') + + if m.IsConstructor: + builder.Append('constructor') + else: + if UseFullyQualifiedMemberNames: + builder.Append(m.FullyQualifiedName) + else: + builder.Append(m.Name) + + if IncludeHTMLMarkup: + builder.Append('') + + builder.Append('(') + if IncludeHTMLMarkup: + builder.Append('
') + + for i in range(m.Parameters.Count): + if IncludeHTMLMarkup: + builder.Append('   ') + + builder.Append(Convert(m.Parameters[i])) + if i + 1 < m.Parameters.Count: + builder.Append(', ') + + if IncludeHTMLMarkup: + builder.Append('
') + + builder.Append(')') + + //if m.ReturnType != null and ShowReturnType and not m.IsConstructor: + if m.ReturnType != null and not m.IsConstructor: + builder.Append(' as ') + builder.Append(Convert(m.ReturnType)) + + if IncludeBodies: + if m.DeclaringType != null: + if m.DeclaringType.ClassType != ClassType.Interface: + builder.Append(': ') + else: + builder.Append(': ') + + + return builder.ToString() + + override def ConvertEnd(m as IMethod) as string: + return '' + + override def Convert(returnType as IReturnType) as string: + if returnType == null: + return '' + + builder as StringBuilder = StringBuilder() + /* + linkSet as bool = false + if UseLinkArrayList: + ret as SharpAssemblyReturnType = returnType as SharpAssemblyReturnType + if ret != null: + if ret.UnderlyingClass != null: + builder.Append('') + linkSet = true + */ + + for i in range(returnType.ArrayCount): + builder.Append('(') + + if returnType.FullyQualifiedName != null and _typeConversionTable[returnType.FullyQualifiedName] != null: + builder.Append(_typeConversionTable[returnType.FullyQualifiedName]) + else: + if UseFullyQualifiedNames: + builder.Append(returnType.FullyQualifiedName) + else: + builder.Append(returnType.Name) + + + //if linkSet: + // builder.Append('') + + if returnType.PointerNestingLevel > 0: + // Sometimes there are negative pointer nesting levels + // (especially in exception constructors in the BCL + for i in range(returnType.PointerNestingLevel): + builder.Append('*') + + for i in range(returnType.ArrayCount): + if returnType.ArrayDimensions[i] > 1: + builder.Append(',') + builder.Append(returnType.ArrayDimensions[i]) + builder.Append(')') + + return builder.ToString() + + override def Convert(param as IParameter) as string: + builder as StringBuilder = StringBuilder() + if IncludeHTMLMarkup: + builder.Append('') + + if param.IsRef: + builder.Append('ref ') + elif param.IsOut: + builder.Append('out ') + elif param.IsParams: + builder.Append('params ') + + if IncludeHTMLMarkup: + builder.Append('') + + if ShowParameterNames: + builder.Append(param.Name) + builder.Append(' as ') + builder.Append(Convert(param.ReturnType)) + + return builder.ToString() + + override def WrapAttribute(attribute as string) as string: + return '[' + attribute + ']' + + override def WrapComment(comment as string) as string: + return '// ' + comment + + override def GetIntrinsicTypeName(dotNetTypeName as string) as string: + if _typeConversionTable[dotNetTypeName] != null: + return _typeConversionTable[dotNetTypeName] + return dotNetTypeName Index: Extras/BooBinding/Gui/IShellModel.boo =================================================================== --- Extras/BooBinding/Gui/IShellModel.boo (revision 0) +++ Extras/BooBinding/Gui/IShellModel.boo (revision 0) @@ -0,0 +1,12 @@ + +namespace BooBinding.Gui + +import System + +interface IShellModel: + def Reset() as bool: + pass + + def ProcessInput (line as String) as (string): + pass + Index: Extras/BooBinding/Gui/BooShellTextView.boo =================================================================== --- Extras/BooBinding/Gui/BooShellTextView.boo (revision 0) +++ Extras/BooBinding/Gui/BooShellTextView.boo (revision 0) @@ -0,0 +1,39 @@ + + + + + +namespace BooBinding.Gui + +import System +import Gtk +import Gdk + + +class ShellTextView (TextView): + + [Getter(Model)] + model as IShellModel + + // FIXME: Do we really want this here? + // Maybe have a constructor that passes the interpreter instead. + _interpreter = InteractiveInterpreter(RememberLastValue: true, Print: PrintObj) + + def constructor(): + self.WrapMode = Gtk.WrapMode.Word + + _interpreter.References.Add(typeof(TextView).Assembly) + _interpreter.References.Add(typeof(Gdk.Key).Assembly) + + _interpreter.SetValue("cls", { Buffer.Text = "" }) + _interpreter.SetValue("view", self) + + def PrintObj(obj): + Buffer.InsertAtCursor("${obj}\n") + + override def OnKeyPressEvent (ev as Gdk.EventKey): + if ev.Key == Gdk.Key.Return: + print ("Return!") + return true + + return super(ev) Index: Extras/BooBinding/Gui/ShellTextView.boo =================================================================== --- Extras/BooBinding/Gui/ShellTextView.boo (revision 0) +++ Extras/BooBinding/Gui/ShellTextView.boo (revision 0) @@ -0,0 +1,234 @@ + +namespace BooBinding.Gui + +import System +import System.Collections +import System.Runtime.InteropServices + +import Gtk +import Gdk +import Pango + +import MonoDevelop.Gui.Widgets +import MonoDevelop.Core.Services +import MonoDevelop.Services +import Boo.IO + + +/* + * TODO + * + * 1) Syntax highlighting? - May be possible using gtksourceview-sharp stuff + * 2) Configurable pieces - Font? Others? + * 3) Don't record lines with errors in the _scriptLines buffer + * 4) Code Completion - Nice way to handle code competion for arbitrary shell? + */ +class ShellTextView (TextView): + private static _promptRegular = ">>> " + private static _promptMultiline = "... " + + [Getter(Model)] + model as IShellModel + + private _scriptLines = "" + + private _commandHistoryPast as Stack = Stack() + private _commandHistoryFuture as Stack = Stack() + + private _inBlock as bool = false + private _blockText = "" + + def constructor(model as IShellModel): + super() + self.model = model + self.WrapMode = Gtk.WrapMode.Word + self.ModifyFont(FontDescription(Family: "Bitstream Vera Sans Mono")) + + // The 'Freezer' tag is used to keep everything except + // the input line from being editable + tag = TextTag ("Freezer") + tag.Editable = false + Buffer.TagTable.Add (tag) + prompt(false) + + #region Overrides of the standard methods for event handling + override def OnPopulatePopup (menu as Gtk.Menu): + _copyScriptInput = ImageMenuItem (GettextCatalog.GetString ("Copy Script")) + _copyScriptInput.Activated += { Gtk.Clipboard.Get (Gdk.Atom.Intern ("PRIMARY", true)).SetText(_scriptLines) } + _copyScriptInput.Image = Gtk.Image (Stock.Copy, Gtk.IconSize.Menu) + + _saveScriptToFile = ImageMenuItem (GettextCatalog.GetString ("Save Script As ...")) + _saveScriptToFile.Image = Gtk.Image (Stock.SaveAs, Gtk.IconSize.Menu) + _saveScriptToFile.Activated += OnSaveScript + + _reset = ImageMenuItem (GettextCatalog.GetString ("Reset Shell")) + _reset.Image = Gtk.Image (Stock.Clear, Gtk.IconSize.Menu) + _reset.Activated += def(): + if Model.Reset(): + resetGui() + + if _scriptLines.Length <= 0: + _copyScriptInput.Sensitive = false + _saveScriptToFile.Sensitive = false + _reset.Sensitive = false + + _sep = Gtk.SeparatorMenuItem() + menu.Prepend(_sep) + menu.Prepend(_copyScriptInput) + menu.Prepend(_saveScriptToFile) + menu.Prepend(_reset) + + _sep.Show() + _copyScriptInput.Show() + _saveScriptToFile.Show() + _reset.Show() + + // FIXME: Handle Shift + PgUp/PgDn? + override def OnKeyPressEvent (ev as Gdk.EventKey): + if ev.Key == Gdk.Key.Return: + if _inBlock: + if InputLine == "": + processInput (_blockText) + _blockText = "" + _inBlock = false + else: + _blockText += "\n${InputLine}" + _whiteSpace = /^(\s+).*/.Replace(InputLine, "$1") + if InputLine.Trim()[-1:] == ":": + _whiteSpace += "\t" + prompt (true, true) + InputLine += "${_whiteSpace}" + else: + // Special case for start of new code block + if InputLine.Trim()[-1:] == ":": + _inBlock = true; + _blockText = InputLine + prompt (true, true) + InputLine += "\t" + return true + + // Bookkeeping + if InputLine != "": + _commandHistoryPast.Push(InputLine) + if _scriptLines == "": + _scriptLines += "${InputLine}" + else: + _scriptLines += "\n${InputLine}" + + processInput (InputLine) + return true + + // The next two cases handle command history + elif ev.Key == Gdk.Key.Up: + if (not _inBlock) and _commandHistoryPast.Count > 0: + _commandHistoryFuture.Push(InputLine) + InputLine = cast (string, _commandHistoryPast.Pop()) + return true + + elif ev.Key == Gdk.Key.Down: + if (not _inBlock) and _commandHistoryFuture.Count > 0: + _commandHistoryPast.Push(InputLine) + InputLine = cast (string, _commandHistoryFuture.Pop()) + return true + + elif ev.Key == Gdk.Key.Left: + // Keep our cursor inside the prompt area + if Cursor.Compare (InputLineBegin) <= 0: + return true + + elif ev.Key == Gdk.Key.Home: + Buffer.MoveMark(Buffer.InsertMark, InputLineBegin) + // Move the selection mark too, if shift isn't held + if (ev.State & Gdk.ModifierType.ShiftMask) == ev.State: + Buffer.MoveMark(Buffer.SelectionBound, InputLineBegin) + return true + + // Needed so people can copy and paste, but always end up + // typing in the prompt. + if Cursor.Compare(InputLineBegin) < 0: + Buffer.MoveMark(Buffer.SelectionBound, InputLineEnd) + Buffer.MoveMark(Buffer.InsertMark, InputLineEnd) + + return super(ev) + + #endregion + + #region Public getters for useful values + public InputLineBegin as TextIter: + get: + iter = Buffer.GetIterAtLine(Buffer.LineCount) + // Really should be either _promptRegular or Multiline, but + // those are the same length + iter.ForwardChars(_promptRegular.Length) + return iter + + public InputLineEnd as TextIter: + get: + return Buffer.EndIter + + private Cursor as TextIter: + get: + return Buffer.GetIterAtMark (Buffer.InsertMark) + #endregion + + // The current input line + public InputLine as string: + get: + return Buffer.GetText (InputLineBegin, InputLineEnd, false) + set: + start = InputLineBegin + end = InputLineEnd + Buffer.Delete (start, end) + start = InputLineBegin + Buffer.Insert (start, value) + + #region local private methods + private def processInput (line as string): + // Send our input out to be processed by the model + // and handle any output received in return + _results = self.Model.ProcessInput (line) + if _results: + for line as string in _results: + processOutput (line) + prompt(true) + + private def processOutput (line as string): + end = Buffer.EndIter + Buffer.Insert (end , "\n${line}") + + private def prompt (newLine as bool): + prompt (newLine, false) + + private def prompt (newLine as bool, multiline as bool): + end = Buffer.EndIter + if newLine: + Buffer.Insert (end , "\n") + if multiline: + Buffer.Insert (end , "${_promptMultiline}") + else: + Buffer.Insert (end , "${_promptRegular}") + + Buffer.PlaceCursor (Buffer.EndIter) + ScrollMarkOnscreen(Buffer.InsertMark) + // Freeze all the text except our input line + Buffer.ApplyTag(Buffer.TagTable.Lookup("Freezer"), Buffer.StartIter, InputLineBegin) + + private def resetGui(): + Buffer.Text = "" + _scriptLines = "" + _commandHistoryFuture.Clear() + _commandHistoryPast.Clear() + prompt(false) + + // FIXME: Make my FileChooser use suck less + private def OnSaveScript(): + _sel = FileSelector("Save Script ...", FileChooserAction.Save) + _sel.Run() + if _sel.Filename: + _sel.Hide() + _path = _sel.Filename + TextFile.WriteFile (_path, _scriptLines) + else: + _sel.Hide() + + #endregion Index: Extras/BooBinding/Gui/BooShellModel.boo =================================================================== --- Extras/BooBinding/Gui/BooShellModel.boo (revision 0) +++ Extras/BooBinding/Gui/BooShellModel.boo (revision 0) @@ -0,0 +1,61 @@ + +namespace BooBinding.Gui + +import System +import System.Collections +import System.IO +import Boo.Lang.Interpreter +import Boo.Lang.Compiler + +class BooShellModel(IShellModel): + + _interpreter = InteractiveInterpreter(RememberLastValue: true, Print: print) + + _outSink as StreamWriter + _outSource as StreamReader + + def constructor(): + _stream = MemoryStream() + _outSink = StreamWriter(_stream) + _outSource = StreamReader (_stream) + + def Reset() as bool: + _interpreter.Reset() + return true + + def ProcessInput (line as String) as (string): + // Make sure our fake stdout is at the beginning + _outSink.BaseStream.SetLength(0) + _outSink.BaseStream.Seek(0, SeekOrigin.Begin) + + // Save tradition stdout, and redirect Console + // to local StreamWriter. Catches any print, etc calls + // to be output to the local shell + _stdout = Console.Out + Console.SetOut(_outSink) + + _interpreter.LoopEval(line) + + // Restore stdout, and prep our fake stdout for reading + Console.SetOut(_stdout) + _outSink.Flush() + _outSink.BaseStream.Seek(0, SeekOrigin.Begin) + + retList = ArrayList() + _outputLine as string = _outSource.ReadLine() + + while _outputLine is not null: + retList.Add(_outputLine) + _outputLine = _outSource.ReadLine() + + ret = cast ((string), retList.ToArray(typeof(string))) + + _ = _interpreter.LastValue + if _ is not null: + print "Setting _ to ${_}" + _interpreter.SetValue("_", _) + + return ret + + def print(obj): + print "${obj}" Index: Extras/BooBinding/Gui/CodeCompilationPanel.boo =================================================================== --- Extras/BooBinding/Gui/CodeCompilationPanel.boo (revision 0) +++ Extras/BooBinding/Gui/CodeCompilationPanel.boo (revision 0) @@ -0,0 +1,174 @@ +// +// +// +// +// +// + +namespace BooBinding + +import System +import Gtk + +import MonoDevelop.Internal.Project +import MonoDevelop.Internal.ExternalTool +import MonoDevelop.Gui.Dialogs +import MonoDevelop.Gui.Widgets +import MonoDevelop.Services +import MonoDevelop.Core.Services +import MonoDevelop.Core.Properties +import MonoDevelop.Core.AddIns.Codons + +public class CodeGenerationPanel(AbstractOptionPanel): + private codeGenerationLabel = Gtk.Label () + private labelWarnings = Gtk.Label () + private labelOutputDir = Gtk.Label () + private outputLabel = Gtk.Label () + private labelCompiler = Gtk.Label () + private labelCulture = Gtk.Label () + + private labelCompileTarget = Gtk.Label () + private compileTargetCombo = Gtk.ComboBox () + + private browseButton as Button + + private checkDebug = CheckButton (GettextCatalog.GetString ("Enable debug")) + private checkDucky = CheckButton (GettextCatalog.GetString ("Enable ducky mode")) + + // compiler chooser + private booc = RadioButton ("booc") + private boo as RadioButton + + private outputAssembly = Entry () + private outputDirectory = Entry () + private compilerPath = Entry () + private culture = Entry () + + compilerParameters as BooCompilerParameters = null + configuration as DotNetProjectConfiguration = null + + def SelectFolder(sender as object , e as EventArgs ) as void: + using fdiag = FolderDialog (GettextCatalog.GetString ("Browse")): + if (fdiag.Run () == cast(int, ResponseType.Ok)): + print "FOO!" + //textBox3.Text = fdiag.Path; + fdiag.Hide () + + public def constructor(): + + InitializeComponent () + vbox = VBox () + hboxCodeGeneration= HBox () + hboxCodeGeneration.PackStart (codeGenerationLabel, false, false, 0) + vbox.PackStart (hboxCodeGeneration) + tableOutputOptions = Table (4, 2, false) + tableOutputOptions.Attach (outputLabel, 0, 1, 0, 1, AttachOptions.Shrink, AttachOptions.Shrink, 0, 0) + tableOutputOptions.Attach (outputAssembly, 1, 2, 0, 1, AttachOptions.Expand | AttachOptions.Fill, AttachOptions.Expand | AttachOptions.Fill, 0, 0) + tableOutputOptions.Attach (labelOutputDir, 0, 1, 1, 2, AttachOptions.Shrink, AttachOptions.Shrink, 0, 0) + tableOutputOptions.Attach (outputDirectory, 1, 2, 1, 2, AttachOptions.Expand | AttachOptions.Fill, AttachOptions.Expand | AttachOptions.Fill, 0, 0) + tableOutputOptions.Attach (labelCompileTarget, 0, 1, 2, 3, AttachOptions.Shrink, AttachOptions.Shrink, 0, 0) + //tableOutputOptions.Attach (compileTargetCombo, 1, 2, 2, 3, AttachOptions.Expand | AttachOptions.Fill, AttachOptions.Expand | AttachOptions.Fill, 0, 0) + tableOutputOptions.Attach (compileTargetCombo, 1, 2, 2, 3, AttachOptions.Fill, AttachOptions.Fill, 0, 0) + tableOutputOptions.Attach (labelCulture, 0, 1, 3, 4, AttachOptions.Shrink, AttachOptions.Shrink, 0, 0) + tableOutputOptions.Attach (culture, 1, 2, 3, 4, AttachOptions.Expand | AttachOptions.Fill, AttachOptions.Expand | AttachOptions.Fill, 0, 0) + vbox.PackStart (tableOutputOptions) + /* + hboxCompiler = HBox () + hboxCompiler.PackStart (labelCompiler, false, false, 0) + vbox.PackStart (hboxCompiler, true, true, 0) + comps = VBox () + comps.PackStart (boo, false, false, 0) + comps.PackStart (booc, false, false, 0) + vbox.PackStart (comps) + vbox.PackStart (compilerPath) + */ + hboxWarnings = HBox () + hboxWarnings.PackStart (labelWarnings, false, false, 0) + vbox.PackStart (hboxWarnings) + vboxChecks = VBox () + vboxChecks.PackStart (checkDebug, false, false, 0) + vboxChecks.PackStart (checkDucky, false, false, 0) + vbox.PackStart (vboxChecks) + Add (vbox) + //self.CustomizationObjectChanged += SetValues + + def OnCompilerToggled (o as object, args as EventArgs) as void: + if booc.Active: + compilerPath.Text = "booc" + else: + compilerPath.Text = "boo" + + private def InitializeComponent() as void: + boo = RadioButton (booc, "boo") + boo.Toggled += OnCompilerToggled + booc.Toggled += OnCompilerToggled + + browseButton = Button ("_Browse") + browseButton.Clicked += SelectFolder + codeGenerationLabel.Markup = String.Format ("{0}", GettextCatalog.GetString ("Code Generation")) + labelOutputDir.Markup = String.Format ("{0} :", GettextCatalog.GetString ("Output Path")) + outputAssembly = Entry () + outputLabel.Markup = String.Format ("{0} :", GettextCatalog.GetString ("Output Assembly")) + labelWarnings.Markup = String.Format ("{0}", GettextCatalog.GetString ("Warnings and Compiler Options")) + + labelCompiler.Markup = String.Format ("{0}", GettextCatalog.GetString ("Compiler")) + labelCulture.Markup = String.Format ("{0} :", GettextCatalog.GetString ("Culture")) + labelCompileTarget.Markup = String.Format ("{0} :", GettextCatalog.GetString ("Output Assembly")) + + typeArray = array(System.Type, 1) + typeArray[0] = typeof(string) + store = ListStore (typeArray) + + stringArray = array(System.String, 1) + stringArray[0] = GettextCatalog.GetString ("Executable") + store.AppendValues (stringArray) + + stringArray = array(System.String, 1) + stringArray[0] = GettextCatalog.GetString ("Library") + store.AppendValues (stringArray) + + /* + stringArray = array(System.String, 1) + stringArray[0] = GettextCatalog.GetString ("Windows Executable") + store.AppendValues (stringArray) + */ + + compileTargetCombo.Model = store + cr = CellRendererText() + compileTargetCombo.PackStart(cr, true) + compileTargetCombo.AddAttribute(cr, "text", 0) + + + public override def LoadPanelContents() as void: + configuration = cast(DotNetProjectConfiguration,(cast(IProperties,CustomizationObject)).GetProperty("Config")) + compilerParameters = cast (BooCompilerParameters, configuration.CompilationParameters) + + if (compilerParameters.Compiler == BooCompiler.Booc): + booc.Active = true + else: + boo.Active = true + + checkDebug.Active = configuration.DebugMode + checkDucky.Active = compilerParameters.Ducky + outputAssembly.Text = configuration.OutputAssembly + outputDirectory.Text = configuration.OutputDirectory + + compilerPath.Text = compilerParameters.CompilerPath + culture.Text = compilerParameters.Culture + compileTargetCombo.Active = cast (int, configuration.CompileTarget) + + public override def StorePanelContents() as bool: + if (compilerParameters is null): + return true + + + configuration.DebugMode = checkDebug.Active + configuration.CompileTarget = cast (CompileTarget, compileTargetCombo.Active) + configuration.OutputAssembly = outputAssembly.Text + configuration.OutputDirectory = outputDirectory.Text + + compilerParameters.Ducky = checkDucky.Active + compilerParameters.CompilerPath = compilerPath.Text + compilerParameters.Culture = culture.Text + + return true Index: Extras/BooBinding/BooShellPadContent.boo =================================================================== --- Extras/BooBinding/BooShellPadContent.boo (revision 0) +++ Extras/BooBinding/BooShellPadContent.boo (revision 0) @@ -0,0 +1,37 @@ + + +namespace BooBinding.Pads + +import System + +import MonoDevelop.Core.AddIns +import MonoDevelop.Services +import MonoDevelop.Core.Services +import MonoDevelop.Gui +import BooBinding.Gui + + +public class BooShellPadContent (AbstractPadContent): + private static _scroller as Gtk.ScrolledWindow + private static _shellView as ShellTextView + + override Control: + get: + return _scroller + + def constructor(): + super( "Boo Shell", "md-boo-binding-base" ) + CreateBooShell() + + def CreateBooShell(): + _scroller = Gtk.ScrolledWindow() + _shellView = ShellTextView (BooShellModel()) + _scroller.Add(_shellView) + + override def RedrawContent(): + OnTitleChanged(null); + OnIconChanged(null); + + override def Dispose(): + _shellView.Dispose() + Index: Extras/BooBinding/Project/BooCompilerParameters.boo =================================================================== --- Extras/BooBinding/Project/BooCompilerParameters.boo (revision 0) +++ Extras/BooBinding/Project/BooCompilerParameters.boo (revision 0) @@ -0,0 +1,64 @@ +// +// +// +// +// +// + +namespace BooBinding + +import System +import System.Xml +import System.Diagnostics + +import MonoDevelop.Internal.Project +import MonoDevelop.Internal.Serialization + +/// +/// This class handles project specific compiler parameters +/// +public class BooCompilerParameters: + [ItemProperty ("compiler")] + compiler = BooCompiler.Booc + + [ItemProperty("compilerpath")] + compilerpath = "booc" + + [ItemProperty("genwarnings")] + genwarnings = false + + [ItemProperty("ducky")] + ducky = false + + [ItemProperty("culture")] + culture = "" + + public GenWarnings as bool: + get: + return genwarnings + set: + genwarnings = value + + public Compiler as BooCompiler: + get: + return compiler + set: + compiler = value + + public CompilerPath as string: + get: + return compilerpath + set: + compilerpath = value + + public Ducky as bool: + get: + return ducky + set: + ducky = value + + public Culture as string: + get: + return culture + set: + culture = value Index: Extras/BooBinding/BooBindingCompilerServices.boo =================================================================== --- Extras/BooBinding/BooBindingCompilerServices.boo (revision 0) +++ Extras/BooBinding/BooBindingCompilerServices.boo (revision 0) @@ -0,0 +1,167 @@ +// +// +// +// +// +// + +namespace BooBinding + +import System +import System.Diagnostics +import System.IO +import System.CodeDom.Compiler +import System.Text + +import MonoDevelop.Gui.Components +import MonoDevelop.Services +import MonoDevelop.Core.Services +import MonoDevelop.Internal.Project + +public class BooBindingCompilerServices: + public def CanCompile (fileName as string): + return Path.GetExtension(fileName) == ".boo" + + public def GetCompilerName (cp as BooCompilerParameters): + if (cp.Compiler == BooCompiler.Boo): + return "boo" + + return "booc" + + def Compile (projectFiles as ProjectFileCollection, references as ProjectReferenceCollection, configuration as DotNetProjectConfiguration, monitor as IProgressMonitor) as ICompilerResult: + compilerparameters = cast(BooCompilerParameters, configuration.CompilationParameters) + if compilerparameters is null: + compilerparameters = BooCompilerParameters() + + // FIXME: Use outdir + //outdir = configuration.OutputDirectory + options = "" + + compiler = GetCompilerName (compilerparameters) + + if configuration.DebugMode: + options += " -debug " + + options += " -o:" + configuration.CompiledOutputName + + if references is not null: + for lib as ProjectReference in references: + fileName = lib.GetReferencedFileName() + // FIXME: DO we need all these tests? + if lib.ReferenceType == ReferenceType.Gac: + options += " -r:" + fileName + " " + elif lib.ReferenceType == ReferenceType.Assembly: + options += " -r:" + fileName + " " + elif lib.ReferenceType == ReferenceType.Project: + options += " -r:" + fileName + " " + + files = "" + + for finfo as ProjectFile in projectFiles: + if finfo.Subtype != Subtype.Directory: + if finfo.BuildAction == BuildAction.Compile: + files = files + " \"" + finfo.Name + "\"" + + + // FIXME: Add selection of output assembly types (library, exe, etc) + if configuration.CompileTarget == CompileTarget.Exe: + options += " -t:exe " + elif configuration.CompileTarget == CompileTarget.Library: + options += " -t:library " + elif configuration.CompileTarget == CompileTarget.WinExe: + options += " -t:winexe " + + if compilerparameters.Culture != String.Empty: + options += " -c:${compilerparameters.Culture} " + + if compilerparameters.Ducky: + options += " -ducky " + + options += files + + tf = TempFileCollection () + output, error = DoCompilation (monitor, compiler, options, tf, configuration, compilerparameters) + cr = ParseOutput (tf, output, error) + File.Delete (output) + File.Delete (error) + return cr + + private def DoCompilation (monitor as IProgressMonitor , compiler as string , args as string , tf as TempFileCollection , configuration as DotNetProjectConfiguration , compilerparameters as BooCompilerParameters): + output = Path.GetTempFileName () + error = Path.GetTempFileName () + + try: + monitor.BeginTask (null, 2) + monitor.Log.WriteLine ("Compiling Boo source code ...") + arguments = String.Format ("-c \"{0} {1} > {2} 2> {3}\"", (compiler, args, output, error)) + si = ProcessStartInfo ("/bin/sh", arguments) + // print "${si.FileName}, ${si.Arguments}" + si.RedirectStandardOutput = true + si.RedirectStandardError = true + si.UseShellExecute = false + p = Process () + p.StartInfo = si + p.Start () + p.WaitForExit () + + monitor.Step (1) + + return output, error; + ensure: + monitor.EndTask () + + + def ParseOutput (tf as TempFileCollection , stdout as string, stderr as string) as ICompilerResult: + compilerOutput = StringBuilder () + cr = CompilerResults (tf) + + for s as string in ( stdout, stderr ): + sr = File.OpenText (s); + while true: + next = sr.ReadLine () + if next is null: + break + + error = CreateErrorFromString (next) + + if error is not null: + cr.Errors.Add (error) + + sr.Close () + + return DefaultCompilerResult (cr, compilerOutput.ToString ()) + + private static def CreateErrorFromString (error as string) as CompilerError: + //print "${error}" + // FIXME: Better checking to make sure we have an error we can parse + + err_pieces = /:/.Split(error) + + // FIXME: i18n of "Fatal Error" check + if err_pieces.Length == 2 and err_pieces[0] == "Fatal error": + cerror = CompilerError() + cerror.ErrorText = error + return cerror + + if (err_pieces.Length < 3): + return null + + // Uses extensive LastIndexOf to avoid problems with filenames + // and directories with "(" or ")" in their names + last_open_bracket = err_pieces[0].LastIndexOf("(") + last_close_bracket = err_pieces[0].LastIndexOf(")") + + file = err_pieces[0].Substring(0,last_open_bracket) + line, column = /,/.Split (err_pieces[0].Substring (last_open_bracket + 1, last_close_bracket - last_open_bracket - 1)) + + cerror = CompilerError () + + // Rejoin the split error back the way it originally was + cerror.ErrorText = join(err_pieces[1:], ":") + cerror.FileName = file + cerror.Column = Int32.Parse(column) + cerror.Line = Int32.Parse(line) + if (err_pieces[2].Trim() == "WARNING"): + cerror.IsWarning = true + + return cerror Index: Extras/BooBinding/BooBinding.addin.xml =================================================================== --- Extras/BooBinding/BooBinding.addin.xml (revision 0) +++ Extras/BooBinding/BooBinding.addin.xml (revision 0) @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: Extras/BooBinding/BooCompiler.boo =================================================================== --- Extras/BooBinding/BooCompiler.boo (revision 0) +++ Extras/BooBinding/BooCompiler.boo (revision 0) @@ -0,0 +1,6 @@ +namespace BooBinding +import System + +public enum BooCompiler: + Booc + Boo Index: Extras/BooBinding/Makefile.am =================================================================== --- Extras/BooBinding/Makefile.am (revision 0) +++ Extras/BooBinding/Makefile.am (revision 0) @@ -0,0 +1,93 @@ + +ADDIN_BUILD = $(top_builddir)/build/AddIns/BackendBindings +ASSEMBLY = $(ADDIN_BUILD)/BooBinding.dll + +DLLS = -r:System.Drawing \ + -r:System.Xml \ + -r:$(top_builddir)/build/bin/MonoDevelop.Core.dll \ + -r:$(top_builddir)/build/bin/MonoDevelop.SourceEditor.dll \ + -r:$(top_builddir)/build/bin/MonoDevelop.Base.dll \ + -r:$(top_builddir)/build/bin/ICSharpCode.SharpRefactory.dll \ + -r:$(top_builddir)/build/bin/MonoDevelop.Gui.Widgets.dll \ + $(BOO_LIBS) \ + $(GTK_SHARP_LIBS) + +FILES = \ +Gui/CodeCompilationPanel.boo \ +Gui/ShellTextView.boo \ +Gui/IShellModel.boo \ +Gui/BooShellModel.boo \ +Project/BooCompilerParameters.boo \ +BooBindingCompilerServices.boo \ +BooAmbience.boo \ +BooShellPadContent.boo \ +BooCompiler.boo \ +BooLanguageBinding.boo \ +Parser/BooParser.boo \ +Parser/Resolver.boo \ +Parser/TypeMembers.boo \ +Parser/ExpressionFinder.boo \ +Parser/ReturnType.boo \ +Parser/VariableLookupVisitor.boo \ +Parser/ExpressionTypeVisitor.boo \ +Parser/Tree.boo \ +Parser/Visitor.boo + +TEMPLATES = \ +templates/BooGtkSharpProject.xpt.xml \ +templates/BooGtkSharpWindow.xft.xml \ +templates/EmptyBooFile.xft.xml \ +templates/EmptyBooProject.xpt.xml + +build_sources = $(addprefix $(srcdir)/, $(FILES)) + +ADDIN = BooBinding.addin.xml + + +TEMPLATES_DIR = $(ADDIN_BUILD)/templates + +build_TEMPLATES = $(addprefix $(TEMPLATES_DIR)/, $(notdir $(TEMPLATES))) + +src_TEMPLATES = $(addprefix $(srcdir)/, $(TEMPLATES)) + +if ENABLE_BOO +all: $(ASSEMBLY) $(ADDIN_BUILD)/$(ADDIN) $(build_TEMPLATES) +else +all: +endif + +#%.xft.xml: $(srcdir)/templates/%.xft.xml +# mkdir -p $(TEMPLATES_DIR) +# cp $(srcdir)/templates/$(notdir $@) $@ +# +#%.xpt.xml: $(srcdir)/templates/%.xpt.xml +# mkdir -p $(TEMPLATES_DIR) +# cp $(srcdir)/templates/$(notdir $@) $@ + +$(filter %.xft.xml, $(build_TEMPLATES)): $(TEMPLATES_DIR)/%.xft.xml: $(srcdir)/templates/%.xft.xml + mkdir -p $(TEMPLATES_DIR) + cp $(srcdir)/templates/$(notdir $@) $@ + +$(filter %.xpt.xml, $(build_TEMPLATES)): $(TEMPLATES_DIR)/%.xpt.xml: $(srcdir)/templates/%.xpt.xml + mkdir -p $(TEMPLATES_DIR) + cp $(srcdir)/templates/$(notdir $@) $@ + +$(ADDIN_BUILD)/$(ADDIN): $(srcdir)/$(ADDIN) + mkdir -p $(ADDIN_BUILD) + cp $(srcdir)/$(ADDIN) $(ADDIN_BUILD)/. + +$(ASSEMBLY): $(FILES) + mkdir -p $(ADDIN_BUILD) + booc $(DLLS) $(build_sources) -o:$@ -t:library + +if ENABLE_BOO +assemblydir = $(libdir)/monodevelop/AddIns/BackendBindings +assembly_DATA = $(ASSEMBLY) $(ADDIN) + +templatedir = $(assemblydir)/templates +template_DATA = $(TEMPLATES) +endif + +CLEANFILES = $(ASSEMBLY) $(ASSEMBLY).mdb +EXTRA_DIST = $(FILES) $(ADDIN) $(TEMPLATES) + Index: Extras/BooBinding/Parser/ExpressionTypeVisitor.boo =================================================================== --- Extras/BooBinding/Parser/ExpressionTypeVisitor.boo (revision 0) +++ Extras/BooBinding/Parser/ExpressionTypeVisitor.boo (revision 0) @@ -0,0 +1,262 @@ +#region license +// Copyright (c) 2004, Daniel Grunwald (daniel@danielgrunwald.de) +// All rights reserved. +// +// BooBinding is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// BooBinding is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with BooBinding; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#endregion + +namespace BooBinding.Parser + +import System +import System.Collections +import MonoDevelop.Internal.Parser +import Boo.Lang.Compiler.Ast + +class ExpressionTypeVisitor(DepthFirstVisitor): + protected override def OnError(node as Node, error as Exception): + //BooParser.ShowException(error) + super(node, error) + + [Property(ReturnType)] + _returnType as IReturnType + + [Property(ReturnClass)] + _returnClass as IClass + + [Property(Resolver)] + _resolver as Resolver + + private def CreateReturnType(fullClassName as string): + _returnClass = null + if fullClassName == null: + _returnType = null + else: + print "CreateReturnType: type set to ${fullClassName}" + _returnType = BooBinding.Parser.ReturnType(fullClassName) + + private def CreateReturnType(reference as TypeReference): + _returnClass = null + if reference == null: + _returnType = null + else: + _returnType = BooBinding.Parser.ReturnType(reference) + + private def CreateReturnType(c as IClass): + _returnClass = c + if c == null: + _returnType = null + else: + _returnType = BooBinding.Parser.ReturnType(c) + + private def SetReturnType(r as IReturnType): + _returnClass = null + _returnType = r + + private def Debug(node): + if node == null: + print "-- null --" + else: + print "${node.ToString()} - ${node.GetType().FullName}" + + override def OnCallableBlockExpression(node as CallableBlockExpression): + Debug(node) + CreateReturnType("System.Delegate") + + override def OnMethodInvocationExpression(node as MethodInvocationExpression): + Debug(node) + Debug(node.Target) + if node.Target isa MemberReferenceExpression: + // call a method on another object + mre as MemberReferenceExpression = node.Target + Visit(mre.Target) + if _returnClass == null and _returnType != null: + _returnClass = _resolver.SearchType(_returnType.FullyQualifiedName) + return if ProcessMethod(node, mre.Name, _returnClass) + // try if the MemberReferenceExpression is a fully qualified class name (constructor call) + ProcessMemberReferenceExpression(mre.Name) + CreateReturnType(_returnClass) + elif node.Target isa ReferenceExpression: + re as ReferenceExpression = node.Target + // try if it is a method on the current object + return if ProcessMethod(node, re.Name, _resolver.CallingClass) + // try if it is a builtin method + return if ProcessMethod(node, re.Name, _resolver.BuiltinClass) + // try if it is a class name -> constructor + CreateReturnType(_resolver.SearchType(re.Name)) + else: + SetReturnType(null) + + private def ProcessMethod(node as MethodInvocationExpression, name as string, c as IClass) as bool: + return false if c == null + possibleOverloads = FindMethods(c, name, node.Arguments.Count) + print "found ${possibleOverloads.Count} overloads (multiple overloads not supported yet)" + if possibleOverloads.Count >= 1: + SetReturnType(cast(IMethod, possibleOverloads[0]).ReturnType) + return true + /*// find best overload + argumentTypes = array(IReturnType, node.Arguments.Count) + for i as int in range(argumentTypes.Length): + Visit(node.Arguments[i]) + argumentTypes[i] = _returnType + ... + */ + return false + + private def FindMethods(c as IClass, name as string, arguments as int): + possibleOverloads = ArrayList() + //for cl as IClass in c.ClassInheritanceTree: + for cl as IClass in _resolver.ParserService.GetClassInheritanceTree(_resolver.Project, c): + for m as IMethod in cl.Methods: + if m.Parameters.Count == arguments and name == m.Name: + possibleOverloads.Add(m) + return possibleOverloads + + override def OnSlicingExpression(node as SlicingExpression): + Debug(node) + Visit(node.Target) + slice as Slice = node.Indices[0] + if (slice.End != null): + // Boo slice, returns a part of the source -> same type as source + return + if _returnType != null and _returnType.ArrayDimensions != null and _returnType.ArrayDimensions.Length > 0: + SetReturnType(BooBinding.Parser.ReturnType(_returnType.FullyQualifiedName, _returnType.ArrayDimensions[0 : _returnType.ArrayDimensions.Length - 1], 0)) + return + if _returnClass == null and _returnType != null: + _returnClass = _resolver.SearchType(_returnType.FullyQualifiedName) + if _returnClass != null: + indexers = FindIndexer(_returnClass, 1) + if indexers.Count > 0: + SetReturnType(cast(IIndexer, indexers[0]).ReturnType) + return + SetReturnType(null) + + private def FindIndexer(c as IClass, arguments as int): + possibleOverloads = ArrayList() + //for cl as IClass in c.ClassInheritanceTree: + for cl as IClass in _resolver.ParserService.GetClassInheritanceTree(_resolver.Project, c): + for m as IIndexer in cl.Indexer: + if m.Parameters.Count == arguments: + possibleOverloads.Add(m) + return possibleOverloads + + override def OnBinaryExpression(node as BinaryExpression): + Debug(node) + CombineTypes(node.Left, node.Right) + + override def OnTernaryExpression(node as TernaryExpression): + Debug(node) + CombineTypes(node.TrueValue, node.FalseValue) + + private def CombineTypes(a as Expression, b as Expression): + Visit(a) + + override def OnReferenceExpression(node as ReferenceExpression): + // Resolve reference (to a variable, field, parameter or type) + rt = _resolver.GetTypeFromLocal(node.Name) + if rt != null: + SetReturnType(rt) + + return if ProcessMember(node.Name, _resolver.CallingClass) + if _resolver.IsNamespace(node.Name): + SetReturnType(NamespaceReturnType(node.Name)) + else: + CreateReturnType(_resolver.SearchType(node.Name)) + + override def OnMemberReferenceExpression(node as MemberReferenceExpression): + Debug(node) + Visit(node.Target) + ProcessMemberReferenceExpression(node.Name) + + private def ProcessMemberReferenceExpression(name as string): + """Gets the return type of the MemberReferenceExpression with the specified name + on the current return type.""" + if _returnType isa NamespaceReturnType: + name = _returnType.FullyQualifiedName + '.' + name + if _resolver.IsNamespace(name): + SetReturnType(NamespaceReturnType(name)) + else: + CreateReturnType(_resolver.SearchType(name)) + return + if _returnClass == null and _returnType != null: + _returnClass = _resolver.SearchType(_returnType.FullyQualifiedName) + return if ProcessMember(name, _returnClass) + SetReturnType(null) + + private def ProcessMember(name as string, parentClass as IClass): + return false if parentClass == null + for cl as IClass in _resolver.ParserService.GetClassInheritanceTree(_resolver.Project, parentClass): + for c as IClass in cl.InnerClasses: + if c.Name == name: + CreateReturnType(c) + return true + for f as IField in cl.Fields: + if f.Name == name: + SetReturnType(f.ReturnType) + return true + for p as IProperty in cl.Properties: + if p.Name == name: + print "ProcessMember: Set property return type to ${p.ReturnType}" + SetReturnType(p.ReturnType) + return true + for m as IMethod in cl.Methods: + if m.Name == name: + CreateReturnType("System.Delegate") + return true + return false + + override def OnTimeSpanLiteralExpression(node as TimeSpanLiteralExpression): + CreateReturnType("System.TimeSpan") + + override def OnIntegerLiteralExpression(node as IntegerLiteralExpression): + CreateReturnType("System.Int32") + + override def OnDoubleLiteralExpression(node as DoubleLiteralExpression): + CreateReturnType("System.Double") + + override def OnNullLiteralExpression(node as NullLiteralExpression): + CreateReturnType("System.Object") + + override def OnStringLiteralExpression(node as StringLiteralExpression): + CreateReturnType("System.String") + + override def OnSelfLiteralExpression(node as SelfLiteralExpression): + CreateReturnType(_resolver.CallingClass) + + override def OnSuperLiteralExpression(node as SuperLiteralExpression): + CreateReturnType(_resolver.ParentClass) + + override def OnBoolLiteralExpression(node as BoolLiteralExpression): + CreateReturnType("System.Boolean") + + override def OnRELiteralExpression(node as RELiteralExpression): + CreateReturnType("System.Text.RegularExpressions.Regex") + + override def OnHashLiteralExpression(node as HashLiteralExpression): + CreateReturnType("System.Collections.Hashtable") + + override def OnListLiteralExpression(node as ListLiteralExpression): + CreateReturnType("System.Collections.ArrayList") + + override def OnArrayLiteralExpression(node as ArrayLiteralExpression): + CreateReturnType("System.Array") + + override def OnAsExpression(node as AsExpression): + CreateReturnType(node.Type) + + override def OnCastExpression(node as CastExpression): + CreateReturnType(node.Type) + + override def OnTypeofExpression(node as TypeofExpression): + CreateReturnType("System.Type") Index: Extras/BooBinding/Parser/Resolver.boo =================================================================== --- Extras/BooBinding/Parser/Resolver.boo (revision 0) +++ Extras/BooBinding/Parser/Resolver.boo (revision 0) @@ -0,0 +1,461 @@ +#region license +// Copyright (c) 2004, Daniel Grunwald (daniel@danielgrunwald.de) +// All rights reserved. +// +// BooBinding is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// BooBinding is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with BooBinding; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#endregion + +namespace BooBinding.Parser + +import BooBinding +import System +import System.Collections +import System.Diagnostics +import System.IO +import MonoDevelop.Services +import MonoDevelop.Internal.Parser +import MonoDevelop.Internal.Project +import Boo.Lang.Compiler +import Boo.Lang.Compiler.Ast as AST +import Boo.Lang.Compiler.IO +import Boo.Lang.Compiler.Steps + +class Resolver: + [Getter(ParserService)] + _parserService as IParserService + + _caretLine as int + _caretColumn as int + + [Getter(Project)] + _project as Project + + [Getter(CallingClass)] + _callingClass as IClass + _compilationUnit as ICompilationUnit + + [Property(ShowStatic)] + _showStatic as bool + + _parentClass as IClass + ParentClass as IClass: + get: + curClass = GetInnermostClass(_compilationUnit) as IClass + return BaseClass(curClass) + + _resolvedMember = false + _currentMember as IMember + + CurrentMember as IMember: + get: + if not _resolvedMember: + _resolvedMember = true + _currentMember = ResolveCurrentMember() + return _currentMember + + + def constructor (): + pass + + def constructor (project as Project): + _project = project + + #region Helper methods + private def ResolveCurrentMember() as IMember: + print "Getting current method... caretLine = ${_caretLine}, caretColumn = ${_caretColumn}" + return null if _callingClass == null + best as IMember = null + line = 0 + for m as IMember in _callingClass.Methods: + if m.Region != null: + if m.Region.BeginLine <= _caretLine and m.Region.BeginLine > line: + line = m.Region.BeginLine + best = m + for m as IMember in _callingClass.Properties: + if m.Region != null: + if m.Region.BeginLine <= _caretLine and m.Region.BeginLine > line: + line = m.Region.BeginLine + best = m + if _callingClass.Region == null: + for m as IMember in _callingClass.Methods: + if m.Region == null: + if best == null or best.Region.EndLine < _caretLine: + return m + return best + + _localTypes as Hashtable = {} + + def GetTypeFromLocal(name as string) as IReturnType: + // gets the type of a local variable or method parameter + print "Trying to get local variable ${name}..." + return _localTypes[name] if _localTypes.ContainsKey(name) + _localTypes[name] = null // prevent stack overflow by caching null first + rt = InnerGetTypeFromLocal(name) + _localTypes[name] = rt + return rt + + def InnerGetTypeFromLocal(name as string) as IReturnType: + member = self.CurrentMember + Print("member", member) + if member isa BooAbstractMethod: + method as BooAbstractMethod = member + for para as IParameter in method.Parameters: + return para.ReturnType if para.Name == name + if method.Node != null and method.Node.Body != null: + varLookup = VariableLookupVisitor(Resolver: self, LookFor: name) + print "Visiting method body..." + varLookup.Visit(method.Node.Body) + print "Finished visiting method body!" + return varLookup.ReturnType + elif member isa Property: + print "name: ${name}" + property as Property = member + /* + if property.ReturnType isa BooBinding.Parser.InferredReturnType: + print "Return type is an inferred, zapping it!" + return ReturnType("System.Object") + */ + return property.ReturnType if name == "value" + for para as IParameter in property.Parameters: + return para.ReturnType if para.Name == name + if property.Node != null: + varLookup = VariableLookupVisitor(Resolver: self, LookFor: name) + // TODO: visit only the correct body + print "Visiting property body..." + varLookup.Visit(property.Node.Getter) unless property.Node.Getter == null + varLookup.Visit(property.Node.Setter) unless property.Node.Setter == null + print "Finished visiting property body!" + /* + if varLookup.ReturnType is null: + print "null return type!" + return ReturnType("System.Object"); + */ + print "ReturnType: ${varLookup.ReturnType}" + return varLookup.ReturnType + return null + + def SearchType(name as string) as IClass: + expandedName = BooAmbience.ReverseTypeConversionTable[name] + return _parserService.GetClass(_project, expandedName) if expandedName != null + //return _parserService.SearchType(_project, name, _callingClass, _caretLine, _caretColumn) + return _parserService.SearchType(_project, name, _callingClass, null) + + builtinClass as IClass + + BuiltinClass as IClass: + get: + builtinClass = _parserService.GetClass(_project, "Boo.Lang.Builtins") if builtinClass == null + return builtinClass + + def IsNamespace(name as string) as bool: + return _parserService.NamespaceExists(_project, name) + + #endregion + + #region CtrlSpace-Completion + def CtrlSpace(parserService as IParserService, caretLine as int, caretColumn as int, fileName as string) as ArrayList: + _parserService = parserService + _caretLine = caretLine + _caretColumn = caretColumn + result = ArrayList(BooAmbience.TypeConversionTable.Values) + result.Add("System") // system namespace can be used everywhere + + builtinClass = self.BuiltinClass + if builtinClass != null: + for method as IMethod in builtinClass.Methods: + result.Add(method) + + parseInfo = parserService.GetParseInformation(fileName) + cu = parseInfo.MostRecentCompilationUnit as CompilationUnit + _compilationUnit = cu + if cu != null: + curClass = GetInnermostClass(cu) as IClass + _callingClass = curClass + if curClass != null: + result = AddCurrentClassMembers(result, curClass) + result.AddRange(parserService.GetNamespaceContents(_project, curClass.Namespace, true, true)) + for u as IUsing in cu.Usings: + if u != null and (u.Region == null or u.Region.IsInside(caretLine, caretColumn)): + for name as string in u.Usings: + result.AddRange(parserService.GetNamespaceContents(_project, name, true, true)) + for alias as string in u.Aliases.Keys: + result.Add(alias) + member = self.CurrentMember + Print("member", member) + if member != null: + varList as Hashtable = null + if member isa BooAbstractMethod: + method as BooAbstractMethod = member + for para as IParameter in method.Parameters: + result.Add(Field(para.ReturnType, para.Name, ModifierEnum.Private, null)) + if method.Node != null: + varLookup = VariableListLookupVisitor(Resolver: self) + print "Visiting method body..." + varLookup.Visit(cast(BooAbstractMethod, member).Node.Body) + print "Finished visiting method body!" + varList = varLookup.Results + elif member isa Property: + property as Property = member + if property.Node != null: + varLookup = VariableListLookupVisitor(Resolver: self) + // TODO: visit only the correct body + print "Visiting property body..." + varLookup.Visit(property.Node.Getter) unless property.Node.Getter == null + varLookup.Visit(property.Node.Setter) unless property.Node.Setter == null + print "Finished visiting property body!" + varList = varLookup.Results + if varList != null: + for e as DictionaryEntry in varList: + result.Add(Field(e.Value, e.Key, ModifierEnum.Private, null)) + result.AddRange(parserService.GetNamespaceContents(_project, "", true, true)) + return result + + def AddCurrentClassMembers(result as ArrayList, curClass as IClass) as ArrayList: + if self.CurrentMember != null and self.CurrentMember.IsStatic == false: + //result = ListMembers(result, curClass, curClass, false) + result = ListMembers(result, curClass) + // Add static members, but only from this class (not from base classes) + for method as IMethod in curClass.Methods: + result.Add(method) if (method.Modifiers & ModifierEnum.Static) == ModifierEnum.Static + for field as IField in curClass.Fields: + result.Add(field) if (field.Modifiers & ModifierEnum.Static) == ModifierEnum.Static + for property as IProperty in curClass.Properties: + result.Add(property) if (property.Modifiers & ModifierEnum.Static) == ModifierEnum.Static + for e as Event in curClass.Events: + result.Add(e) if (e.Modifiers & ModifierEnum.Static) == ModifierEnum.Static + return result + #endregion + + #region IsAsResolve + + def IsAsResolve(parserService as IParserService, expression as string, caretLine as int, caretColumn as int, fileName as string, fileContent as string) as ArrayList: + return null + + def MonodocResolver(parserService as IParserService, expression as string, caretLine as int, caretColumn as int, fileName as string, fileContent as string) as string: + return null + + #region Resolve CC + def Initialize(parserService as IParserService, caretLine as int, caretColumn as int, fileName as string): + _parserService = parserService + _caretLine = caretLine + _caretColumn = caretColumn + + parseInfo = parserService.GetParseInformation(fileName) + cu = parseInfo.MostRecentCompilationUnit as CompilationUnit + _compilationUnit = cu + if _compilationUnit == null: + print "BooResolver: No parse information!" + return false + _callingClass = GetInnermostClass(cu) + if _callingClass == null: + return false if cu.Classes.Count == 0 + _callingClass = cu.Classes[cu.Classes.Count - 1] + if _callingClass.Region != null: + return false if _callingClass.Region.BeginLine > caretLine + return true + + def Resolve(parserService as IParserService, expression as string, caretLine as int, caretColumn as int, fileName as string, fileContent as string) as ResolveResult: + if expression == null or expression == '': + return null + + if expression.StartsWith("import "): + expression = expression.Substring(7).Trim() + if parserService.NamespaceExists(_project, expression): + return ResolveResult(parserService.GetNamespaceList(_project, expression, true, true)) + return null + + if not Initialize(parserService, caretLine, caretColumn, fileName): + return null + callingClass = _callingClass + returnClass as IClass = null + if expression == "self": + returnClass = callingClass + elif expression == "this": + // SharpDevelop uses "this" as expression when requesting method insight information + // for a method on the current class + returnClass = callingClass + elif expression == "super": + returnClass = self.ParentClass + else: + // try looking if the expression is the name of a class + expressionClass = self.SearchType(expression) + if expressionClass != null: + //return ResolveResult(expressionClass, ListMembers(ArrayList(), expressionClass, callingClass, true)) + return ResolveResult(expressionClass, ListMembers(ArrayList(), expressionClass)) + + // try if it is the name of a namespace + if parserService.NamespaceExists(_project, expression): + return ResolveResult(array(string, 0), parserService.GetNamespaceContents(_project, expression, true, true)) + + expr = Boo.Lang.Parser.BooParser.ParseExpression("expression", expression) + return null if expr isa AST.IntegerLiteralExpression + visitor = ExpressionTypeVisitor(Resolver : self) + visitor.Visit(expr) + retType = visitor.ReturnType + Print ("result", retType) + if visitor.ReturnClass != null: + returnClass = visitor.ReturnClass + elif retType != null: + if retType.ArrayDimensions != null and retType.ArrayDimensions.Length > 0: + returnClass = self.SearchType("System.Array") + else: + returnClass = self.SearchType(retType.FullyQualifiedName) + + return null if returnClass == null + //return ResolveResult(returnClass, ListMembers(ArrayList(), returnClass, callingClass, false)) + return ResolveResult(returnClass, ListMembers(ArrayList(), returnClass)) + + private def Print(name as string, obj): + Console.Write(name) + Console.Write(' = ') + if obj == null: + print('null') + else: + print("${obj} (${obj.GetType().FullName})") + #endregion + + #region Code converted from CSharpBinding/Parser/Resolver.cs + def MustBeShowen(c as IClass, member as IDecoration) as bool: + // FIXME: _showStatic should be coming from elsewhere... but where? (See CSharpBinding) + _showStatic = false +// print("member:" + member.Modifiers); + if (((not _showStatic) and ((member.Modifiers & ModifierEnum.Static) == ModifierEnum.Static)) or + ( _showStatic and not ((member.Modifiers & ModifierEnum.Static) == ModifierEnum.Static))): + //// enum type fields are not shown here - there is no info in member about enum field + return false + +// print("Testing Accessibility"); + return IsAccessible(c, member) + + def IsAccessible(c as IClass, member as IDecoration) as bool: +// print("member.Modifiers = " + member.Modifiers); + if ((member.Modifiers & ModifierEnum.Internal) == ModifierEnum.Internal): + return true + + if ((member.Modifiers & ModifierEnum.Public) == ModifierEnum.Public): +// print("IsAccessible") + return true + + if ((member.Modifiers & ModifierEnum.Protected) == ModifierEnum.Protected and IsClassInInheritanceTree(c, _callingClass)): +// print("IsAccessible") + return true + + return c.FullyQualifiedName == _callingClass.FullyQualifiedName + + /// + /// Returns true, if class possibleBaseClass is in the inheritance tree from c + /// + def IsClassInInheritanceTree(possibleBaseClass as IClass , c as IClass) as bool: + if (possibleBaseClass == null or c == null): + return false + + if (possibleBaseClass.FullyQualifiedName == c.FullyQualifiedName): + return true + + for baseClass as string in c.BaseTypes: + bc = _parserService.GetClass (_project, baseClass, true, true) + if (IsClassInInheritanceTree(possibleBaseClass, bc)): + return true + + return false + + def BaseClass(curClass as IClass) as IClass: + for s as string in curClass.BaseTypes: + baseClass = _parserService.GetClass (_project, s, true, true) + if ((baseClass != null) and (baseClass.ClassType != ClassType.Interface)): + return baseClass + return null + + def ListMembers(members as ArrayList, curType as IClass) as ArrayList: + // FIXME: _showStatic should be coming from elsewhere... but where? (See CSharpBinding) + _showStatic = false +// print("LIST MEMBERS!!!"); +// print("_showStatic = " + _showStatic); +// print(curType.InnerClasses.Count + " classes"); +// print(curType.Properties.Count + " properties"); +// print(curType.Methods.Count + " methods"); +// print(curType.Events.Count + " events"); +// print(curType.Fields.Count + " fields"); + if _showStatic: + for c as IClass in curType.InnerClasses: + if IsAccessible(curType, c): + members.Add(c) +// print("Member added") + + for p as IProperty in curType.Properties: + if (MustBeShowen(curType, p)): + members.Add(p) +// print("Member added") + +// print("ADDING METHODS!!!"); + for m as IMethod in curType.Methods: +// print("Method : " + m) + if (MustBeShowen(curType, m)): + members.Add(m) +// print("Member added"); + + for e as IEvent in curType.Events: + if (MustBeShowen(curType, e)): + members.Add(e) +// print("Member added"); + + for f as IField in curType.Fields: + if (MustBeShowen(curType, f)): + members.Add(f) +// print("Member added") + else: + //// enum fields must be shown here if present + if (curType.ClassType == ClassType.Enum): + members.Add(f) if (IsAccessible(curType,f)) +// print("Member {0} added", f.FullyQualifiedName); + +// print("ClassType = " + curType.ClassType); + if (curType.ClassType == ClassType.Interface and not _showStatic): + for s as string in curType.BaseTypes: + baseClass = _parserService.GetClass (_project, s, true, true) + if (baseClass != null and baseClass.ClassType == ClassType.Interface): + ListMembers(members, baseClass) + else: + baseClass = BaseClass(curType) + if (baseClass != null): +// print("Base Class = " + baseClass.FullyQualifiedName) + ListMembers(members, baseClass) + +// print("listing finished"); + return members; + + def GetResolvedClass (cls as IClass) as IClass: + // Returns an IClass in which all type names have been properly resolved + return _parserService.GetClass (_project, cls.FullyQualifiedName); + + def GetInnermostClass(cu as ICompilationUnit) as IClass: + if (cu != null): + for c as IClass in cu.Classes: + if (c != null and c.Region != null and c.Region.IsInside(_caretLine, _caretColumn)): + return GetInnermostClass(c) + return null; + + def GetInnermostClass(curClass as IClass) as IClass: + if (curClass == null): + return null + + if (curClass.InnerClasses == null): + return GetResolvedClass (curClass) + + for c as IClass in curClass.InnerClasses: + if (c != null and c.Region != null and c.Region.IsInside(_caretLine, _caretColumn)): + return GetInnermostClass(c) + + return GetResolvedClass (curClass) Index: Extras/BooBinding/Parser/ReturnType.boo =================================================================== --- Extras/BooBinding/Parser/ReturnType.boo (revision 0) +++ Extras/BooBinding/Parser/ReturnType.boo (revision 0) @@ -0,0 +1,192 @@ +#region license +// Copyright (c) 2004, Daniel Grunwald (daniel@danielgrunwald.de) +// All rights reserved. +// +// BooBinding is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// BooBinding is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with BooBinding; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#endregion + +namespace BooBinding.Parser + +import System +import System.Collections +import System.Diagnostics +import MonoDevelop.Internal.Parser +import MonoDevelop.Services +import Boo.Lang.Compiler.Ast as AST + +///////////////////////////////////// +/// Return Type /// +///////////////////////////////////// +class ReturnType(AbstractReturnType): + def constructor(fullyQualifiedName as string): + self(fullyQualifiedName, array(int, 0), 0) + + def constructor(fullyQualifiedName as string, arrayDimensions as (int), pointerNestingLevel as int): + self.FullyQualifiedName = fullyQualifiedName + self.arrayDimensions = arrayDimensions + self.pointerNestingLevel = pointerNestingLevel + + def constructor(t as AST.TypeReference): + super.pointerNestingLevel = 0 + if t isa AST.SimpleTypeReference: + super.arrayDimensions = array(int, 0) + name = cast(AST.SimpleTypeReference, t).Name + expandedName = BooBinding.BooAmbience.ReverseTypeConversionTable[name] + name = expandedName if expandedName != null + super.FullyQualifiedName = name + elif t isa AST.ArrayTypeReference: + ar as AST.ArrayTypeReference = t + depth = 1 + while ar.ElementType isa AST.ArrayTypeReference: + depth += 1 + ar = ar.ElementType + dimensions = array(int, depth) + for i as int in range(depth): + dimensions[i] = 1 + self.arrayDimensions = dimensions + if ar.ElementType isa AST.SimpleTypeReference: + super.FullyQualifiedName = cast(AST.SimpleTypeReference, ar.ElementType).Name + else: + print ("Got unknown TypeReference in Array: ${t}") + super.FullyQualifiedName = "" + else: + super.arrayDimensions = array(int, 0) + super.FullyQualifiedName = "" + print ("Got unknown TypeReference ${t}") + + static def CreateReturnType(node as AST.Node) as IReturnType: + if node isa AST.Field: + t = (node as AST.Field).Type + elif node isa AST.Property: + t = (node as AST.Property).Type + elif node isa AST.Method: + t = (node as AST.Method).ReturnType + else: + raise "Unknown node ${node.GetType().FullName}" + str = t as AST.SimpleTypeReference + if (str != null and str.Name != "unknown") or t isa AST.ArrayTypeReference: + return ReturnType(t) + else: + if node isa AST.Field: + return InferredReturnType((node as AST.Field).Initializer, node.LexicalInfo) + elif node isa AST.Property: + prop as AST.Property = node + return InferredReturnType(GetReturnExpression(prop.Getter), node.LexicalInfo) + elif node isa AST.Method: + return InferredReturnType(GetReturnExpression(node), node.LexicalInfo) + + private static def GetReturnExpression(method as AST.Method): + return null if method == null + return null if method.Body == null + visitor = FindReturnExpressionVisitor() + method.Body.Accept(visitor) + return visitor.Expression + + private class FindReturnExpressionVisitor(AST.DepthFirstVisitor): + [Getter(Expression)] + _expression as AST.Expression + + override def OnReturnStatement(node as AST.ReturnStatement): + if _expression isa AST.NullLiteralExpression or not (node.Expression isa AST.NullLiteralExpression): + _expression = node.Expression + + def constructor(t as AST.TypeDefinition): + self(t.FullName) + + def constructor(c as IClass): + self(c.FullyQualifiedName) + + def Clone() as ReturnType: + return ReturnType(FullyQualifiedName, arrayDimensions, pointerNestingLevel) + + override def ToString(): + return "[${GetType().Name} Name=${FullyQualifiedName}]" + +///////////////////////////////////// +/// Namespace Return Type /// +///////////////////////////////////// +class NamespaceReturnType(AbstractReturnType): + def constructor(fullyQualifiedName as string): + self.FullyQualifiedName = fullyQualifiedName + self.arrayDimensions = array(int, 0) + self.pointerNestingLevel = 0 + + override def ToString(): + return "[${GetType().Name} Name=${FullyQualifiedName}]" + +///////////////////////////////////// +/// Inferred Return Type /// +///////////////////////////////////// +class InferredReturnType(AbstractReturnType): + _expression as AST.Expression + + _filename as string + _caretLine as int + _caretColumn as int + + def constructor(expression as AST.Expression, info as AST.LexicalInfo): + _expression = expression + if info == null or expression == null: + _resolved = true // don't resolve but return error + else: + _filename = info.FileName + _caretLine = info.Line + _caretColumn = info.Column + + _baseType as IReturnType + _resolved as bool = false + + override FullyQualifiedName as string: + get: + r = self.BaseType + if r == null: + return "" + else: + return r.FullyQualifiedName + set: + raise NotSupportedException() + + override PointerNestingLevel as int: + get: + r = self.BaseType + if r == null: + return 0 + else: + return r.PointerNestingLevel + + override ArrayDimensions as (int): + get: + r = self.BaseType + if r == null: + return array(int, 0) + else: + return r.ArrayDimensions + + BaseType as IReturnType: + get: + if not _resolved: + _resolved = true + _baseType = Resolve() + return _baseType + + def Resolve() as IReturnType: + resolver = Resolver() + parserService = MonoDevelop.Core.Services.ServiceManager.GetService(typeof(IParserService)) + if resolver.Initialize(parserService, _caretLine, _caretColumn, _filename): + visitor = ExpressionTypeVisitor(Resolver : resolver) + visitor.Visit(_expression) + return visitor.ReturnType + else: + return null Index: Extras/BooBinding/Parser/ExpressionFinder.boo =================================================================== --- Extras/BooBinding/Parser/ExpressionFinder.boo (revision 0) +++ Extras/BooBinding/Parser/ExpressionFinder.boo (revision 0) @@ -0,0 +1,208 @@ +#region license +// Copyright (c) 2004, Daniel Grunwald (daniel@danielgrunwald.de) +// All rights reserved. +// +// BooBinding is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// BooBinding is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with BooBinding; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#endregion + +namespace BooBinding.Parser + +import System +import System.Text +import MonoDevelop.Internal.Parser + +class ExpressionFinder(IExpressionFinder): + // The expression finder can find an expression in a text + // inText is the full source code, offset the cursor position + + // example: "_var = 'bla'\n_var^\nprint _var" + // where ^ is the cursor position + // in that simple case the expression finder should return 'n_var'. + + // but also complex expressions like + // 'filename.Substring(filename.IndexOf("var="))' + // should be returned if the cursor is after the last ). + + // implementation note: the text after offset is irrelevant, so + // every operation on the string aborts after reaching offset + + static _closingBrackets = '}])' + static _openingBrackets = '{[(' + + def FindExpression(inText as string, offset as int) as string: + return null if inText == null + print "Trying quickfind for ${offset}" + // OK, first try a kind of "quick find" + i = offset + 1 + forbidden = '"\'/#)]}' + finish = '([{=+*<,:' + start = -1 + while i > 0: + i -= 1 + c = inText[i] + if finish.IndexOf(c) >= 0: + start = i + 1 + break + if forbidden.IndexOf(c) >= 0: + print "Quickfind failed: got ${c}" + break + if Char.IsWhiteSpace(c): + if i > 6 and inText.Substring(i - 6, 6) == "import": + i -= 7 // include 'import' in the expression + start = i + 1 + break + if start >= 0: + if CheckString(inText, start, '/#"\'', '\r\n'): + return GetExpression(inText, start, offset + 1) + + inText = SimplifyCode(inText, offset) + if inText == null: + print 'SimplifyCode returned null (cursor is in comment/string???)' + return null + // inText now has no comments or string literals, but the same meaning in + // terms of the type system + // Now go back until a finish-character or a whitespace character + bracketStack = StringBuilder() // use Stack instead in .NET 2.0 + i = inText.Length + while i > 0: + i -= 1 + c = inText[i] + if bracketStack.Length == 0 and (finish.IndexOf(c) >= 0 or Char.IsWhiteSpace(c)): + return GetExpression(inText, i + 1, inText.Length) + if _closingBrackets.IndexOf(c) >= 0: + bracketStack.Append(c) + bracket = _openingBrackets.IndexOf(c) + if bracket >= 0: + while Pop(bracketStack) > bracket: + pass + + return null + + private def CheckString(text as string, offset as int, forbidden as string, finish as string): + i = offset + while i > 0: + i -= 1 + c = text[i] + return false if forbidden.IndexOf(c) >= 0 + return true if finish.IndexOf(c) >= 0 + return true + + private def Pop(bracketStack as StringBuilder): + return -1 if bracketStack.Length == 0 + c = bracketStack[bracketStack.Length - 1] + bracketStack.Length -= 1 + return _closingBrackets.IndexOf(c) + + private def GetExpression(inText as string, start as int, end as int): + b = StringBuilder() + wasSpace = true + i = start + while i < end: + c = inText[i] + if Char.IsWhiteSpace(c): + b.Append(' ') unless wasSpace + wasSpace = true + else: + wasSpace = false + b.Append(c) + i += 1 + print "Expression is '${b}'" + return b.ToString().Trim() + + // this method makes boo source code "simpler" by removing all comments + // and replacing all types of strings through string.Empty. + + // TODO: We could need some unit tests for this. + + static _elseIndex = 10 + + static _stateTable = ( // " ' \ \n $ { } # / * else + /* 0: in Code */ ( 1 , 7 , 0 , 0 , 0 , 0 , 0 , 13 , 12 , 0 , 0 ), + /* 1: after " */ ( 2 , 6 , 10 , 0 , 8 , 6 , 6 , 6 , 6 , 6 , 6 ), + /* 2: after "" */ ( 3 , 7 , 0 , 0 , 0 , 0 , 0 , 13 , 12 , 0 , 0 ), + /* 3: in """ */ ( 4 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 ), + /* 4: in """, " */ ( 5 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 ), + /* 5: in """, "" */ ( 0 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 ), + /* 6: in "-string */ ( 0 , 6 , 10 , 0 , 8 , 6 , 6 , 6 , 6 , 6 , 6 ), + /* 7: in '-string */ ( 7 , 0 , 11 , 0 , 7 , 7 , 7 , 7 , 7 , 7 , 7 ), + /* 8: after $ in " */ ( 0 , 6 , 10 , 0 , 8 , 9 , 6 , 6 , 6 , 6 , 6 ), + /* 9: in "{ */ ( 9 , 9 , 9 , 9 , 9 , 9 , 6 , 9 , 9 , 9 , 9 ), + /* 10: after \ in " */ ( 6 , 6 , 6 , 0 , 6 , 6 , 6 , 6 , 6 , 6 , 6 ), + /* 11: after \ in ' */ ( 7 , 7 , 7 , 0 , 7 , 7 , 7 , 7 , 7 , 7 , 7 ), + /* 12: after / */ ( 1 , 7 , 0 , 0 , 0 , 0 , 0 , 0 , 13 ,-14 , 0 ), + /* 13: line comment */ ( 13 , 13 , 13 , 0 , 13 , 13 , 13 , 13 , 13 , 13 , 13 ), + /* 14: block comment*/ ( 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 15 , 14 ), + /* 15: after * in bc*/ ( 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 ,-15 , 15 , 14 ) + ) + + def SimplifyCode(inText as string, offset as int): + result = StringBuilder() + inStringResult = StringBuilder(' ') + state = 0 + commentblocks = 0 + inputTable = array(int, 128) + for i in range(128): + inputTable[i] = _elseIndex + inputTable[ 34] = 0 // " + inputTable[ 39] = 1 // ' + inputTable[ 92] = 2 // \ + inputTable[ 10] = 3 // \n + inputTable[ 13] = 3 // \r + inputTable[ 36] = 4 // $ + inputTable[123] = 5 // { + inputTable[125] = 6 // } + inputTable[ 35] = 7 // # + inputTable[ 47] = 8 // / + inputTable[ 42] = 9 // * + for i in range(offset + 1): + c as Char = inText[i] + // TODO: Direct char->int conversion + charNum as int = Encoding.ASCII.GetBytes((c,))[0] + if charNum > 127: + input = _elseIndex + else: + input = inputTable[charNum] + action = _stateTable[state][input] + if action == -14: + // enter block comment + commentblocks += 1 + state = 14 + elif action == -15: + // leave block comment + commentblocks -= 1 + if commentblocks == 0: + state = 0 + else: + state = 14 + elif action == 9: + if state == 9: + inStringResult.Append(c) + else: + inStringResult.Length = 1 + state = action + elif action == 0 or action == 12: + if state == 2 or (state >= 6 and state <= 11): + result.Append("string.Empty") + if state == 0 or state == 2 or state == 12: + result.Append(c) + state = action + else: + state = action + if state == 0 or state == 2 or state == 12: + return result.ToString() + elif state == 9: + return inStringResult.ToString() + else: + return null Index: Extras/BooBinding/Parser/BooParser.boo =================================================================== --- Extras/BooBinding/Parser/BooParser.boo (revision 0) +++ Extras/BooBinding/Parser/BooParser.boo (revision 0) @@ -0,0 +1,161 @@ +#region license +// Copyright (c) 2004, Daniel Grunwald (daniel@danielgrunwald.de) +// All rights reserved. +// +// BooBinding is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// BooBinding is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with BooBinding; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#endregion + +namespace BooBinding.Parser + +import System +import System.Collections +import System.Diagnostics +import System.IO +import MonoDevelop.Services +//import ICSharpCode.SharpDevelop.Services +import MonoDevelop.Internal.Project +import MonoDevelop.Internal.Parser +import Boo.Lang.Compiler +import Boo.Lang.Compiler.IO +import Boo.Lang.Compiler.Pipelines +import Boo.Lang.Compiler.Steps + +class BooParser(IParser): + private _lexerTags as (string) + + LexerTags as (string): + get: + return _lexerTags + set: + _lexerTags = value + + ExpressionFinder as IExpressionFinder: + get: + return BooBinding.Parser.ExpressionFinder() + + def CanParse(fileName as string): + return Path.GetExtension(fileName).ToLower() == ".boo" + + def CanParse(project as Project): + return project.ProjectType == BooBinding.BooLanguageBinding.LanguageName + + def Parse(fileName as string) as ICompilationUnitBase: + /* + compiler = BooCompiler() + compiler.Parameters.Input.Add(FileInput(fileName)) + return Parse(fileName, compiler) + */ + content as string + using r = StreamReader(fileName): + content = r.ReadToEnd() + return Parse(fileName, content) + + def Parse(fileName as string, fileContent as string) as ICompilationUnitBase: + //print "Parse ${fileName} with content" + + cr = '\r'[0] + ln = '\n'[0] + linecount = 1 + for c as Char in fileContent: + linecount += 1 if c == ln + lineLength = array(int, linecount) + length = 0 + i = 0 + for c as Char in fileContent: + if c == ln: + lineLength[i] = length + i += 1 + length = 0 + elif c != cr: + length += 1 + lineLength[i] = length + + compiler = BooCompiler() + compiler.Parameters.Input.Add(StringInput(fileName, fileContent)) + return Parse(fileName, lineLength, compiler) + + private def Parse(fileName as string, lineLength as (int), compiler as BooCompiler): + compiler.Parameters.OutputWriter = StringWriter() + compiler.Parameters.TraceSwitch.Level = TraceLevel.Warning; + + compilePipe = Compile() + parsingStep as Boo.Lang.Parser.BooParsingStep = compilePipe[0] + parsingStep.TabSize = 1 + num = compilePipe.Find(typeof(StricterErrorChecking)) + // Original cut out from this place onward, but this caused + // problems with [Property(A)]\na\n type properties + // and trying to figure out the types. + // What did we break by doing this extra Step? + //num = compilePipe.Find(typeof(ProcessMethodBodiesWithDuckTyping)) + visitor = Visitor(LineLength:lineLength) + for c as IClass in visitor.Cu.Classes: + c.Region.FileName = fileName + compilePipe[num] = visitor + // Remove unneccessary compiler steps + while compilePipe.Count > num + 1: + compilePipe.RemoveAt(compilePipe.Count - 1) + num = compilePipe.Find(typeof(TransformCallableDefinitions)) + compilePipe.RemoveAt(num) + + //for i in range(compilePipe.Count): + // print compilePipe[i].ToString() + + compilePipe.BreakOnErrors = false + compiler.Parameters.Pipeline = compilePipe + + try: + compiler.Run() + // somehow the SD parser thread goes into an endless loop if this flag is not set + visitor.Cu.ErrorsDuringCompile = true //context.Errors.Count > 0 + except e: + //ShowException(e) + print "ShowException ${e}" + return visitor.Cu + + def CtrlSpace(parserService as IParserService, project as Project, caretLine as int, caretColumn as int, fileName as string) as ArrayList: + //print "Ctrl-Space (${caretLine}/${caretColumn})" + try: + return Resolver(project).CtrlSpace(parserService, caretLine, caretColumn, fileName) + except e: + //ShowException(e) + return null + + def IsAsResolve (parserService as IParserService , project as Project , expression as string , caretLineNumber as int , caretColumn as int , fileName as string , fileContent as string ) as ArrayList: + return Resolver (project).IsAsResolve (parserService, expression, caretLineNumber, caretColumn, fileName, fileContent) + + def Resolve(parserService as IParserService, project as Project, expression as string, caretLineNumber as int, caretColumn as int, fileName as string, fileContent as string) as ResolveResult: + //print "Resolve ${expression} (${caretLineNumber}/${caretColumn})" + try: + return Resolver(project).Resolve(parserService, expression, caretLineNumber, caretColumn, fileName, fileContent) + except e: + //ShowException(e) + return null + + def MonodocResolver(parserService as IParserService, project as Project, expression as string, caretLineNumber as int, caretColumn as int, fileName as string, fileContent as string) as string: + //print "MonodocResolver ${expression} (${caretLineNumber}/${caretColumn})" + try: + return Resolver(project).MonodocResolver(parserService, expression, caretLineNumber, caretColumn, fileName, fileContent) + except e: + //ShowException(e) + return null + + /* + static def ShowException(e as Exception): + //messageService as IMessageService = ServiceManager.Services.GetService(typeof(IMessageService)) + //messageService.ShowError(e.ToString()) + retur + */ + + Index: Extras/BooBinding/Parser/TypeMembers.boo =================================================================== --- Extras/BooBinding/Parser/TypeMembers.boo (revision 0) +++ Extras/BooBinding/Parser/TypeMembers.boo (revision 0) @@ -0,0 +1,128 @@ +#region license +// Copyright (c) 2004, Daniel Grunwald (daniel@danielgrunwald.de) +// All rights reserved. +// +// BooBinding is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// BooBinding is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with BooBinding; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#endregion + +namespace BooBinding.Parser + +import System +import MonoDevelop.Internal.Parser +import Boo.Lang.Compiler.Ast as AST + +///////////////////////////////////// +/// Constructor /// +///////////////////////////////////// +class Constructor(BooAbstractMethod): + def constructor(m as ModifierEnum, region as IRegion, bodyRegion as IRegion): + FullyQualifiedName = '#ctor' + self.region = region + self.bodyRegion = bodyRegion + modifiers = m + + +///////////////////////////////////// +/// Destructor /// +///////////////////////////////////// +class Destructor(BooAbstractMethod): + def constructor(className as string, m as ModifierEnum, region as IRegion, bodyRegion as IRegion): + FullyQualifiedName = '~' + className + self.region = region + self.bodyRegion = bodyRegion + modifiers = m + +class BooAbstractMethod(AbstractMethod): + [Property(Node)] + _node as AST.Method + + def AddModifier(m as ModifierEnum): + modifiers = modifiers | m + +///////////////////////////////////// +/// Event /// +///////////////////////////////////// +class Event(AbstractEvent): + def AddModifier(m as ModifierEnum): + modifiers = modifiers | m + + def constructor(name as string, rtype as IReturnType, m as ModifierEnum, region as IRegion, bodyRegion as IRegion): + FullyQualifiedName = name + returnType = rtype + self.region = region + self.bodyRegion = bodyRegion + modifiers = m + + +///////////////////////////////////// +/// Field /// +///////////////////////////////////// +class Field(AbstractField): + def AddModifier(m as ModifierEnum): + modifiers = modifiers | m + + def constructor(rtype as IReturnType, fullyQualifiedName as string, m as ModifierEnum, region as IRegion): + self.returnType = rtype + self.FullyQualifiedName = fullyQualifiedName + self.region = region + modifiers = m + + def SetModifiers(m as ModifierEnum): + modifiers = m + + +///////////////////////////////////// +/// Indexer /// +///////////////////////////////////// +class Indexer(AbstractIndexer): + def AddModifier(m as ModifierEnum): + modifiers = modifiers | m + + def constructor(rtype as IReturnType, parameters as ParameterCollection, m as ModifierEnum, region as IRegion, bodyRegion as IRegion): + returnType = rtype + self.parameters = parameters + self.region = region + self.bodyRegion = bodyRegion + modifiers = m + + +///////////////////////////////////// +/// Method /// +///////////////////////////////////// +class Method(BooAbstractMethod): + def constructor(name as string, rtype as IReturnType, m as ModifierEnum, region as IRegion, bodyRegion as IRegion): + FullyQualifiedName = name + self.returnType = rtype + self.region = region + self.bodyRegion = bodyRegion + modifiers = m + + +///////////////////////////////////// +/// Property /// +///////////////////////////////////// +class Property(AbstractProperty): + [Property(Node)] + _node as AST.Property + + def AddModifier(m as ModifierEnum): + modifiers = modifiers | m + + def constructor(fullyQualifiedName as string, rtype as IReturnType, m as ModifierEnum, region as IRegion, bodyRegion as IRegion): + self.FullyQualifiedName = fullyQualifiedName + self.returnType = rtype + self.region = region + self.bodyRegion = bodyRegion + modifiers = m Index: Extras/BooBinding/Parser/VariableLookupVisitor.boo =================================================================== --- Extras/BooBinding/Parser/VariableLookupVisitor.boo (revision 0) +++ Extras/BooBinding/Parser/VariableLookupVisitor.boo (revision 0) @@ -0,0 +1,95 @@ +#region license +// Copyright (c) 2004, Daniel Grunwald (daniel@danielgrunwald.de) +// All rights reserved. +// +// BooBinding is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// BooBinding is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with BooBinding; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#endregion + +namespace BooBinding.Parser + +import System +import System.Collections +import MonoDevelop.Internal.Parser +import Boo.Lang.Compiler.Ast + +class VariableLookupVisitor(DepthFirstVisitor): + [Property(Resolver)] + _resolver as Resolver + + [Property(LookFor)] + _lookFor as string + + [Getter(ReturnType)] + _returnType as IReturnType + + private def Finish(expr as Expression): + return if expr == null + return if _returnType != null + visitor = ExpressionTypeVisitor(Resolver: _resolver) + visitor.Visit(expr) + _returnType = visitor.ReturnType + + private def Finish(reference as TypeReference): + return if _returnType != null + return if reference == null + _returnType = BooBinding.Parser.ReturnType(reference) + + override def OnDeclaration(node as Declaration): + return if node.Name != _lookFor + Finish(node.Type) + + override def OnDeclarationStatement(node as DeclarationStatement): + return if node.Declaration.Name != _lookFor + Visit(node.Declaration) + Finish(node.Initializer) + + override def OnBinaryExpression(node as BinaryExpression): + if node.Operator == BinaryOperatorType.Assign and node.Left isa ReferenceExpression: + reference as ReferenceExpression = node.Left + if reference.Name == _lookFor: + Finish(node.Right) unless reference isa MemberReferenceExpression + super(node) + +class VariableListLookupVisitor(DepthFirstVisitor): + [Property(Resolver)] + _resolver as Resolver + + [Getter(Results)] + _results as Hashtable = {} + + private def Add(name as string, expr as Expression): + return if name == null or expr == null + return if _results.ContainsKey(name) + visitor = ExpressionTypeVisitor(Resolver: _resolver) + visitor.Visit(expr) + _results.Add(name, visitor.ReturnType) + + private def Add(name as string, reference as TypeReference): + return if reference == null or name == null + return if _results.ContainsKey(name) + _results.Add(name, BooBinding.Parser.ReturnType(reference)) + + override def OnDeclaration(node as Declaration): + Add(node.Name, node.Type) + + override def OnDeclarationStatement(node as DeclarationStatement): + Visit(node.Declaration) + Add(node.Declaration.Name, node.Initializer) + + override def OnBinaryExpression(node as BinaryExpression): + if node.Operator == BinaryOperatorType.Assign and node.Left isa ReferenceExpression: + reference as ReferenceExpression = node.Left + Add(reference.Name, node.Right) unless reference isa MemberReferenceExpression + super(node) Index: Extras/BooBinding/Parser/Visitor.boo =================================================================== --- Extras/BooBinding/Parser/Visitor.boo (revision 0) +++ Extras/BooBinding/Parser/Visitor.boo (revision 0) @@ -0,0 +1,281 @@ +#region license +// Copyright (c) 2004, Daniel Grunwald (daniel@danielgrunwald.de) +// All rights reserved. +// +// BooBinding is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// BooBinding is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with BooBinding; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#endregion + +namespace BooBinding.Parser + +import System +import System.Collections +import MonoDevelop.Services +import MonoDevelop.Internal.Parser +import Boo.Lang.Compiler +import Boo.Lang.Compiler.Ast as AST +import Boo.Lang.Compiler.IO +import Boo.Lang.Compiler.Steps + +class Using(AbstractUsing): + pass + +class Visitor(AbstractVisitorCompilerStep): + [Getter(Cu)] + _cu as CompilationUnit = CompilationUnit() + + _currentClass as Stack = Stack() + _firstModule = true + + override def Run(): + //print "RUN" + try: + Visit(CompileUnit) + except e: + print e.ToString() + //msg as IMessageService = ServiceManager.Services.GetService(typeof(IMessageService)) + //msg.ShowError(e) + + private def GetModifier(m as AST.TypeMember) as ModifierEnum: + r = ModifierEnum.None + r = r | ModifierEnum.Public if m.IsPublic + r = r | ModifierEnum.Protected if m.IsProtected + r = r | ModifierEnum.Private if m.IsPrivate + r = r | ModifierEnum.Internal if m.IsInternal + + r = r | ModifierEnum.Static if m.IsStatic + r = r | ModifierEnum.Virtual if m.IsModifierSet(AST.TypeMemberModifiers.Virtual) + r = r | ModifierEnum.Abstract if m.IsModifierSet(AST.TypeMemberModifiers.Abstract) + r = r | ModifierEnum.Override if m.IsModifierSet(AST.TypeMemberModifiers.Override) + + r = r | ModifierEnum.Final if m.IsFinal + return r + + [Property(LineLength)] + _lineLength as (int) + + private def GetLineEnd(line as int) as int: + return 0 if _lineLength == null or line < 1 or line > _lineLength.Length + return _lineLength[line - 1] + 1 + + private def GetRegion(m as AST.Node): + l = m.LexicalInfo + return null if (l.Line < 0) + return DefaultRegion(l.Line, 0 /*l.Column*/, l.Line, GetLineEnd(l.Line)) + + private def GetClientRegion(m as AST.Node) as DefaultRegion: + l = m.LexicalInfo + return null if l.Line < 0 + l2 as AST.SourceLocation = null + if m isa AST.Method: + l2 = cast(AST.Method, m).Body.EndSourceLocation + elif m isa AST.Property: + p as AST.Property = m + if p.Getter != null and p.Getter.Body != null: + l2 = cast(AST.Property, m).Getter.Body.EndSourceLocation + if p.Setter != null and p.Setter.Body != null: + l3 = cast(AST.Property, m).Setter.Body.EndSourceLocation + l2 = l3 if l3.Line > l2.Line + elif p.Setter != null and p.Setter.Body != null: + l2 = cast(AST.Property, m).Setter.Body.EndSourceLocation + else: + l2 = m.EndSourceLocation + return null if l2 == null or l2.Line < 0 or l.Line == l2.Line + // TODO: use l.Column / l2.Column when the tab-bug has been fixed + return DefaultRegion(l.Line, GetLineEnd(l.Line), l2.Line, GetLineEnd(l2.Line)) + + override def OnImport(p as AST.Import): + u = Using() + if p.Alias == null: + u.Usings.Add(p.Namespace) + else: + u.Aliases[p.Alias.Name] = p.Namespace + _cu.Usings.Add(u) + + override def OnCallableDefinition(node as AST.CallableDefinition): + //print "OnCallableDefinition: ${node.FullName}" + region = GetRegion(node) + modifier = GetModifier(node) + c = Class(_cu, ClassType.Delegate, modifier, region) + c.BaseTypes.Add('System.Delegate') + c.FullyQualifiedName = node.FullName + if _currentClass.Count > 0: + cast(Class, _currentClass.Peek()).InnerClasses.Add(c) + else: + _cu.Classes.Add(c) + invokeMethod = Method('Invoke', ReturnType(node.ReturnType), modifier, region, region) + invokeMethod.Parameters = GetParameters(node.Parameters) + c.Methods.Add(invokeMethod) + + override def EnterClassDefinition(node as AST.ClassDefinition): + EnterTypeDefinition(node, ClassType.Class) + return super(node) + + override def EnterInterfaceDefinition(node as AST.InterfaceDefinition): + EnterTypeDefinition(node, ClassType.Interface) + return super(node) + + override def EnterEnumDefinition(node as AST.EnumDefinition): + EnterTypeDefinition(node, ClassType.Enum) + return super(node) + + override def EnterModule(node as AST.Module): + EnterTypeDefinition(node, ClassType.Class) unless _firstModule + _firstModule = false + return super(node) + + private def EnterTypeDefinition(node as AST.TypeDefinition, classType as ClassType): + try: + //print "Enter ${node.GetType().Name} (${node.FullName})" + region = GetClientRegion(node) + modifier = GetModifier(node) + c = Class(_cu, classType, modifier, region) + c.FullyQualifiedName = node.FullName + c.Documentation = node.Documentation + if _currentClass.Count > 0: + cast(Class, _currentClass.Peek()).InnerClasses.Add(c) + else: + _cu.Classes.Add(c) + if node.BaseTypes != null: + for r as AST.SimpleTypeReference in node.BaseTypes: + c.BaseTypes.Add(r.Name) + _currentClass.Push(c) + except ex: + print ex.ToString() + raise + + override def LeaveClassDefinition(node as AST.ClassDefinition): + LeaveTypeDefinition(node) + super(node) + + override def LeaveInterfaceDefinition(node as AST.InterfaceDefinition): + LeaveTypeDefinition(node) + super(node) + + override def LeaveEnumDefinition(node as AST.EnumDefinition): + LeaveTypeDefinition(node) + super(node) + + override def LeaveModule(node as AST.Module): + LeaveTypeDefinition(node) unless _currentClass.Count == 0 + super(node) + + private def LeaveTypeDefinition(node as AST.TypeDefinition): + c as Class = _currentClass.Pop() + //print "Leave ${node.GetType().Name} ${node.FullName} (Class = ${c.FullyQualifiedName})" + c.UpdateModifier() + + override def OnMethod(node as AST.Method): + try: + // Since we visit after ProcessMethodBodies, we may have + // some compiler generated methods (prefixed with ___) + if node.Name.StartsWith("___"): + return + + print "Method: ${node.FullName}" + method = Method(node.Name, ReturnType.CreateReturnType(node), GetModifier(node), GetRegion(node), GetClientRegion(node)) + method.Parameters = GetParameters(node.Parameters) + method.Node = node + method.Documentation = node.Documentation + cast(Class, _currentClass.Peek()).Methods.Add(method) + except ex: + print ex.ToString() + raise + + private def GetParameters(params as AST.ParameterDeclarationCollection): + parameters = ParameterCollection() + return parameters if params == null + for par as AST.ParameterDeclaration in params: + parameters.Add(Parameter(par.Name, ReturnType(par.Type))) + return parameters + + override def OnConstructor(node as AST.Constructor): + return if node.Body.Statements.Count == 0 + ctor = Constructor(GetModifier(node), GetRegion(node), GetClientRegion(node)) + ctor.Parameters = GetParameters(node.Parameters) + ctor.Node = node + ctor.Documentation = node.Documentation + cast(Class, _currentClass.Peek()).Methods.Add(ctor) + + override def OnEnumMember(node as AST.EnumMember): + try: + c as Class = _currentClass.Peek() + field = Field(ReturnType(c), node.Name, GetModifier(node), GetRegion(node)) + field.Documentation = node.Documentation + field.SetModifiers(ModifierEnum.Const | ModifierEnum.SpecialName) + c.Fields.Add(field) + except x: + print x + raise + + override def OnField(node as AST.Field): + try: + //print "Field ${node.Name}" + c as Class = _currentClass.Peek() + field = Field(ReturnType.CreateReturnType(node), node.Name, GetModifier(node), GetRegion(node)) + field.Documentation = node.Documentation + c.Fields.Add(field) + except ex: + print ex.ToString() + raise + + override def OnProperty(node as AST.Property): + try: + property = Property(node.Name, ReturnType.CreateReturnType(node), GetModifier(node), GetRegion(node), GetClientRegion(node)) + property.Documentation = node.Documentation + property.Node = node + cast(Class, _currentClass.Peek()).Properties.Add(property) + except ex: + print ex.ToString() + raise + + /* + // TODO: Event Declaration + override def Visit(eventDeclaration as AST.EventDeclaration, data as object) as object: + region as DefaultRegion = GetRegion(eventDeclaration.StartLocation, eventDeclaration.EndLocation) + bodyRegion as DefaultRegion = GetRegion(eventDeclaration.BodyStart, eventDeclaration.BodyEnd) + type as ReturnType = ReturnType(eventDeclaration.TypeReference) + c as Class = _currentClass.Peek() + e as Event = null + if eventDeclaration.VariableDeclarators != null: + for varDecl as ICSharpCode.SharpRefactory.Parser.AST.VariableDeclaration in eventDeclaration.VariableDeclarators: + e = Event(varDecl.Name, type, eventDeclaration.Modifier, region, bodyRegion) + c.Events.Add(e) + + else: + e = Event(eventDeclaration.Name, type, eventDeclaration.Modifier, region, bodyRegion) + c.Events.Add(e) + + return null + + // TODO: Detect indexer method and add it as Indexer + override def Visit(indexerDeclaration as AST.IndexerDeclaration, data as object) as object: + region as DefaultRegion = GetRegion(indexerDeclaration.StartLocation, indexerDeclaration.EndLocation) + bodyRegion as DefaultRegion = GetRegion(indexerDeclaration.BodyStart, indexerDeclaration.BodyEnd) + parameters as ParameterCollection = ParameterCollection() + i as Indexer = Indexer(ReturnType(indexerDeclaration.TypeReference), parameters, indexerDeclaration.Modifier, region, bodyRegion) + if indexerDeclaration.Parameters != null: + for par as AST.ParameterDeclarationExpression in indexerDeclaration.Parameters: + parType as ReturnType = ReturnType(par.TypeReference) + p as Parameter = Parameter(par.ParameterName, parType) + parameters.Add(p) + + + c as Class = _currentClass.Peek() + c.Indexer.Add(i) + return null + */ + + + Index: Extras/BooBinding/Parser/Tree.boo =================================================================== --- Extras/BooBinding/Parser/Tree.boo (revision 0) +++ Extras/BooBinding/Parser/Tree.boo (revision 0) @@ -0,0 +1,121 @@ +#region license +// Copyright (c) 2004, Daniel Grunwald (daniel@danielgrunwald.de) +// All rights reserved. +// +// BooBinding is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// BooBinding is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with BooBinding; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#endregion + +namespace BooBinding.Parser + +import System +import System.Collections +import System.Diagnostics +import MonoDevelop.Internal.Parser +import Boo.Lang.Compiler.Ast as AST + +///////////////////////////////////// +/// Compilation Unit /// +///////////////////////////////////// +class CompilationUnit(AbstractCompilationUnit): + override MiscComments as CommentCollection: + get: + return null + + override DokuComments as CommentCollection: + get: + return null + + override TagComments as TagCollection: + get: + return null + +///////////////////////////////////// +/// Class /// +///////////////////////////////////// +class Class(AbstractClass): + _cu as ICompilationUnit + + override CompilationUnit as ICompilationUnit: + get: + return _cu + + def constructor(cu as CompilationUnit, t as ClassType, m as ModifierEnum, region as IRegion): + _cu = cu + classType = t + self.region = region + modifiers = m + + def UpdateModifier(): + if classType == ClassType.Enum: + for f as Field in Fields: + f.AddModifier(ModifierEnum.Public) + + return + + for f as Field in Fields: + if f.Modifiers == ModifierEnum.None: + f.AddModifier(ModifierEnum.Protected) + + if classType != ClassType.Interface: + return + + for c as Class in InnerClasses: + c.modifiers = c.modifiers | ModifierEnum.Public + + for m as IMethod in Methods: + if m isa BooAbstractMethod: + cast(BooAbstractMethod, m).AddModifier(ModifierEnum.Public) + else: + Debug.Assert(false, 'Unexpected type in method of interface. Can not set modifier to public!') + + for e as Event in Events: + e.AddModifier(ModifierEnum.Public) + + for f as Field in Fields: + f.AddModifier(ModifierEnum.Public) + + for i as Indexer in Indexer: + i.AddModifier(ModifierEnum.Public) + + for p as Property in Properties: + p.AddModifier(ModifierEnum.Public) + + + + +///////////////////////////////////// +/// Parameter /// +///////////////////////////////////// +class Parameter(AbstractParameter): + def constructor(name as string, rtype as ReturnType): + Name = name + returnType = rtype + +///////////////////////////////////// +/// Attributes /// +///////////////////////////////////// +class AttributeSection(AbstractAttributeSection): + def constructor(attributeTarget as AttributeTarget, attributes as AttributeCollection): + self.attributeTarget = attributeTarget + self.attributes = attributes + +class ASTAttribute(AbstractAttribute): + def constructor(name as string, positionalArguments as ArrayList, namedArguments as SortedList): + self.name = name + self.positionalArguments = positionalArguments + self.namedArguments = namedArguments + + + Index: Extras/BooBinding/BooLanguageBinding.boo =================================================================== --- Extras/BooBinding/BooLanguageBinding.boo (revision 0) +++ Extras/BooBinding/BooLanguageBinding.boo (revision 0) @@ -0,0 +1,56 @@ +// +// +// +// +// +// + +namespace BooBinding + +import System +import System.IO +import System.Diagnostics +import System.Collections +import System.Reflection +import System.Resources +import System.Xml + +import MonoDevelop.Internal.Project +import MonoDevelop.Internal.Templates +import MonoDevelop.Gui +import MonoDevelop.Services + +/// +/// This class describes the main functionalaty of a language binding +/// +public class BooLanguageBinding(ILanguageBinding): + internal static LanguageName = "Boo" + compilerServices = BooBindingCompilerServices () + + public def constructor(): + MonoDevelop.Services.Runtime.ProjectService.DataContext.IncludeType (typeof(BooCompilerParameters)); + + public Language as string: + get: + return LanguageName + + public def CanCompile(fileName as string) as bool: + Debug.Assert(compilerServices is not null) + return compilerServices.CanCompile(fileName) + + public def Compile (projectFiles as ProjectFileCollection , references as ProjectReferenceCollection , configuration as DotNetProjectConfiguration , monitor as IProgressMonitor ) as ICompilerResult: + Debug.Assert(compilerServices is not null) + return compilerServices.Compile (projectFiles, references, configuration, monitor) + + public def GenerateMakefile (project as Project, parentCombine as Combine) as void: + // FIXME: dont abort for now + // throw NotImplementedException () + return + + public def CreateCompilationParameters (projectOptions as XmlElement) as object: + parameters = BooCompilerParameters () + return parameters + + public CommentTag as string: + get: + return "//"; Index: Extras/BooBinding/templates/BooGtkSharpProject.xpt.xml =================================================================== --- Extras/BooBinding/templates/BooGtkSharpProject.xpt.xml (revision 0) +++ Extras/BooBinding/templates/BooGtkSharpProject.xpt.xml (revision 0) @@ -0,0 +1,49 @@ + + + Index: Extras/BooBinding/templates/BooGtkSharpWindow.xft.xml =================================================================== --- Extras/BooBinding/templates/BooGtkSharpWindow.xft.xml (revision 0) +++ Extras/BooBinding/templates/BooGtkSharpWindow.xft.xml (revision 0) @@ -0,0 +1,29 @@ + + Index: Extras/BooBinding/templates/EmptyBooFile.xft.xml =================================================================== --- Extras/BooBinding/templates/EmptyBooFile.xft.xml (revision 0) +++ Extras/BooBinding/templates/EmptyBooFile.xft.xml (revision 0) @@ -0,0 +1,20 @@ + + Index: Extras/BooBinding/templates/EmptyBooProject.xpt.xml =================================================================== --- Extras/BooBinding/templates/EmptyBooProject.xpt.xml (revision 0) +++ Extras/BooBinding/templates/EmptyBooProject.xpt.xml (revision 0) @@ -0,0 +1,19 @@ + +