Rubberduck: Support for semicolon on object.print

Created on 2 Apr 2019  路  14Comments  路  Source: rubberduck-vba/Rubberduck

Rubberduck version information
The info below can be copy-paste-completed from the first lines of Rubberduck's log or the About box:

Rubberduck version 2.4.1.4627
Operating System: Win 10
Host Product: Microsoft Visual Basic 6.0

Description
It seems vb6 allows a semi colon on the Print line to suppress CRLF. It seems to be an exception but it is making parsing fail on my [very old and large] code base.

more info: https://stackoverflow.com/questions/9290731/what-is-the-effect-of-a-semicolon-at-the-end-of-a-line

Logfile

2019-04-02 16:40:03.7484;ERROR-2.4.1.4627;Rubberduck.Parsing.VBA.Parsing.ModuleParser;Syntax error; offending token ';' at line 746, column 21 in the CodePaneCode version of module modGeneral.;
2019-04-02 16:40:03.7484;DEBUG-2.4.1.4627;Rubberduck.Parsing.VBA.Parsing.ModuleParser;SyntaxErrorException thrown in thread 10, ParseTaskID f8b54930-1b42-4137-9da1-c1dfbab69269.;Rubberduck.Parsing.VBA.Parsing.ParsingExceptions.MainParseSyntaxErrorException: extraneous input ';' expecting {<EOF>, ':', REM, NEWLINE, ''', WS, LINE_CONTINUATION}
   at Rubberduck.Parsing.VBA.Parsing.ParsingExceptions.MainParseExceptionErrorListener.SyntaxError(IRecognizer recognizer, IToken offendingSymbol, Int32 line, Int32 charPositionInLine, String msg, RecognitionException e) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ParsingExceptions\MainParseExceptionErrorListener.cs:line 14
   at Antlr4.Runtime.ProxyErrorListener`1.SyntaxError(IRecognizer recognizer, Symbol offendingSymbol, Int32 line, Int32 charPositionInLine, String msg, RecognitionException e)
   at Antlr4.Runtime.Parser.NotifyErrorListeners(IToken offendingToken, String msg, RecognitionException e)
   at Antlr4.Runtime.DefaultErrorStrategy.ReportUnwantedToken(Parser recognizer)
   at Antlr4.Runtime.DefaultErrorStrategy.SingleTokenDeletion(Parser recognizer)
   at Antlr4.Runtime.DefaultErrorStrategy.Sync(Parser recognizer)
   at Rubberduck.Parsing.Grammar.VBAParser.endOfStatement() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 20219
   at Rubberduck.Parsing.Grammar.VBAParser.block() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 2303
   at Rubberduck.Parsing.Grammar.VBAParser.ifStmt() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 8893
   at Rubberduck.Parsing.Grammar.VBAParser.mainBlockStmt() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 2707
   at Rubberduck.Parsing.Grammar.VBAParser.blockStmt() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 2461
   at Rubberduck.Parsing.Grammar.VBAParser.block() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 2302
   at Rubberduck.Parsing.Grammar.VBAParser.subStmt() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 12721
   at Rubberduck.Parsing.Grammar.VBAParser.moduleBodyElement() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 2238
   at Rubberduck.Parsing.Grammar.VBAParser.moduleBody() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 2131
   at Rubberduck.Parsing.Grammar.VBAParser.module() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 446
   at Rubberduck.Parsing.Grammar.VBAParser.startRule() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 334
   at Rubberduck.Parsing.VBA.Parsing.VBATokenStreamParser.Parse(ITokenStream tokenStream, PredictionMode predictionMode, IParserErrorListener errorListener) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\VBATokenStreamParser.cs:line 21
   at Rubberduck.Parsing.VBA.Parsing.TokenStreamParserBase.ParseLl(String moduleName, ITokenStream tokenStream, CodeKind codeKind) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\TokenStreamParserBase.cs:line 75
   at Rubberduck.Parsing.VBA.Parsing.TokenStreamParserBase.ParseWithFallBack(String moduleName, CommonTokenStream tokenStream, CodeKind codeKind) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\TokenStreamParserBase.cs:line 52
   at Rubberduck.Parsing.VBA.Parsing.TokenStreamParserBase.Parse(String moduleName, CommonTokenStream tokenStream, CodeKind codeKind, ParserMode parserMode) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\TokenStreamParserBase.cs:line 32
   at Rubberduck.Parsing.VBA.Parsing.TokenStreamParserStringParserAdapterWithPreprocessing.Parse(String moduleName, String projectId, String code, CancellationToken token, CodeKind codeKind, ParserMode parserMode) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\TokenStreamParserStringParserAdapterWithPreprocessing.cs:line 29
   at Rubberduck.Parsing.VBA.Parsing.ModuleParser.CodePanePassResults(QualifiedModuleName module, CancellationToken token, TokenStreamRewriter rewriter) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ModuleParser.cs:line 165
   at Rubberduck.Parsing.VBA.Parsing.ModuleParser.ParseInternal(QualifiedModuleName module, CancellationToken cancellationToken, TokenStreamRewriter rewriter, Guid taskId) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ModuleParser.cs:line 84
   at Rubberduck.Parsing.VBA.Parsing.ModuleParser.Parse(QualifiedModuleName module, CancellationToken cancellationToken, TokenStreamRewriter rewriter) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ModuleParser.cs:line 40
Token: ; at L746C21
Kind of parsed code: CodePaneCode
Component: modGeneral (code pane version)
ParseType: Main parse

Additional context
Basically the line causing the issue is

obj.Print a$;
antlr bug difficulty-03-duck hacktoberfest

All 14 comments

Thanks for the feedback! This parser bug has been reported as part of another issue last week - let's keep both open, and make the older one specific to the issue with Line statements.

ref. #4875

Ah I'm sorry - the title didn't give me any hints 馃槅

@mika76 no problem! we very much prefer having a single bug per issue, makes it easier to associate commits with a specific issue :smiley:

So I made a quick little DLL to try and see how the VBE actually works, made it COM-visible, exposing a Print method:

Print member showing with keyword highlighting in the VBE

The Print member gets keyword syntax highlighting, which is a tell-tale sign something is going on at the language level. The code compiles, but running it throws run-time error 438 "member not found"; invoking PrintMethodTest.Class1.DoSomething correctly does nothing, as expected (implementations for both methods was left empty / no-op).

There is no apparent way to have a Print method that's an invokable member that doesn't support the trailing comma/semicolon shenanigans - not in user code (Sub Print() is illegal, Print is reserved), not in referenced type libraries.

Hence, seems we need to forbid Print as a member call, and special-case Print calls to support trailing comma/semicolons, regardless of what's qualifying them - not just Debug.

I'm not 100% but I think they can be separators as well as trailing. Both comma and semicolon

@mika76 that's correct - basically the parser rule we have for special-casing Debug.Print :+1:

@retailcoder Try implementing this IVBPrint interface on your test Class1

[
  odl,
  uuid(000204F0-0000-0000-C000-000000000046),
  nonextensible
]
interface IVBPrint : IUnknown {
    HRESULT _stdcall WriteText([in] BSTR strText);
    [propput]
    HRESULT _stdcall Column([in] long retVal);
    [propget]
    HRESULT _stdcall Column([out, retval] long* retVal);
};

I'm very curious too if this works. . .

Error 438 Member not found is the wrong way to say IVBPrint interface not found :-))

Interesting. Never have seen IVBPrint interface before. In where is it defined?

On Access where Print with comma/semicolon works on an Access.Report object, the OLE viewer does not show it having that interface.

I'm not sure its documented and I don't have it in my HKLM\Classes\Interface too.

Its IID is in pretty system family of IIDs:

{00020400-0000-0000-C000-000000000046} IDispatch
{00020401-0000-0000-C000-000000000046} ITypeInfo
{00020402-0000-0000-C000-000000000046} ITypeLib
{00020403-0000-0000-C000-000000000046} ITypeComp
{00020404-0000-0000-C000-000000000046} IEnumVARIANT
. . .

Second result of google search by its IID is where I got it from.

I guess this is the 2nd result of google search (It was 4th for me)

VBForums hijacking psuedomethods

Interesting -- apparently Circle/Pset/Print/etc. pseudo methods are in fact just a bunch of APIs under the hood. The link had a side discussion about how to override the Circle method and provide custom behavior.

That also means we can in theory check whether a call to Print is valid by checking if the type implements the undocumented interface.

Try implementing this IVBPrint interface on your test Class1

Just as a FYI - this seems to be documented now

Hey @retailcoder this is great stuff! Any idea when your next stable release will be? Last one was in march...

The current plan is early to mid November.

@MDoerner fantastic thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Gener4tor picture Gener4tor  路  3Comments

ghost picture ghost  路  3Comments

retailcoder picture retailcoder  路  3Comments

Inarion picture Inarion  路  3Comments

Hosch250 picture Hosch250  路  3Comments