SyntaxHighlighter2.st
changeset 13844 c2938013239e
parent 13313 de38ade7083d
child 14056 1b0f6f3c4bbd
--- a/SyntaxHighlighter2.st	Wed Feb 05 19:59:07 2014 +0100
+++ b/SyntaxHighlighter2.st	Wed Feb 05 19:59:09 2014 +0100
@@ -26,7 +26,8 @@
 "{ Package: 'stx:libtool' }"
 
 SyntaxHighlighter subclass:#SyntaxHighlighter2
-	instanceVariableNames:'elements lastVariableElements lastSelectorElement'
+	instanceVariableNames:'elements lastVariableElements lastSelectorElement
+		ignoreBadIdentifier'
 	classVariableNames:''
 	poolDictionaries:''
 	category:'Interface-CodeView-Syntax'
@@ -132,16 +133,54 @@
     "format (recolor) an expression in a given class.
      Return the text containing font changes and color information."
 
-    ^ self 
-        format:aString parsingWith:[:parser | parser expression]
-        in:aClass elementsInto:elements
+    |parser tree text endPos|
+
+    aString isNil ifTrue:[^ nil].
+
+    parser := self for:(ReadStream on:aString string) in:aClass.
+    parser elements: elements.
+    parser ignoreErrors:true.
+    parser ignoreWarnings:true.
+    parser sourceText:(text := aString string asText).
+    "/ use an array here - this can be changed much faster using #at:put:
+    text emphasisCollection:(Array new:aString size).
+
+    parser nextToken.
+    tree := parser "expression"statementList.
+    "/ now, convert the emphasis-array to a runArray
+    text emphasisCollection:(text emphasis asRunArray).
+
+    tree == #Error ifTrue:[
+	"/ mhmh - which is better ...
+	"/ alternative1: color rest after error in red
+"/        text
+"/            emphasizeFrom:(parser sourceStream position)
+"/            to:text size
+"/            with:(#color->Color red).
+
+
+	"/ alternative2: take original emphasis for rest
+
+	endPos := parser sourceStream position1Based.
+	endPos >= text size ifTrue:[
+	    ^ text
+	].
+	^ ((text copyTo:endPos) , (aString copyFrom:(endPos+1))).
+
+	"/ alternative3: no emphasis for rest.
+
+"/        ^ text "/ aString
+    ].
+    ^ text
 
     "
      self
-        formatExpression:'(1 + 2) max:5' 
-        in:UndefinedObject
-        elementsInto:(OrderedCollection new)
+	formatExpression:'(1 + 2) max:5'
+	in:UndefinedObject
     "
+
+    "Created: / 25-07-2010 / 08:56:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 25-07-2010 / 10:57:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 formatMethod:aString in:aClass using:preferencesOrNil elementsInto: elements
@@ -169,7 +208,7 @@
 
     Error handle:[:ex |
         ex creator isHandled ifTrue:[
-            ex reject.    
+            ex reject.
         ].
         (self parseErrorSignal handles:ex) ifFalse:[
             "Parse error may happen when re-formatting incomplete code while editing"
@@ -196,9 +235,9 @@
             eColor notNil ifTrue:[
                 "/ mhmh - which is better ...
                 "/ alternative1: color rest after error in red
-                text 
+                text
                     emphasizeFrom:(highlighter sourceStream position + 1) 
-                    to:text size 
+                    to:text size
                     with:(#color->eColor).
             ] ifFalse:[
                 "/ alternative2: take original emphasis for rest
@@ -211,11 +250,11 @@
             ].
             "/ alternative3: no emphasis for rest.
         ].
-        ^text 
+        ^text
     ]
     "
      self
-        formatMethod:'foo 
+        formatMethod:'foo
     ^ self bar:''hello''.
 
     ' , (Character doubleQuote asString) , 'some comment' , (Character doubleQuote asString) , '
@@ -225,6 +264,7 @@
 
     "Modified: / 22-08-2006 / 13:32:04 / cg"
     "Created: / 05-07-2011 / 10:39:21 / cg"
+    "Modified: / 28-05-2013 / 22:45:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 formatStatementList:aString in:aClass elementsInto: elements
@@ -249,12 +289,19 @@
     ^ elements
 !
 
-elements:something
+elements:aParseTreeIndex
     "the element collection, to collect variables, selectors etc. into"
 
-    elements := something.
+    elements := aParseTreeIndex.
 
     "Modified (comment): / 21-08-2011 / 09:13:31 / cg"
+!
+
+tree: aParseNode
+    super tree: aParseNode.
+    elements tree: aParseNode
+
+    "Created: / 16-02-2012 / 09:56:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !SyntaxHighlighter2 methodsFor:'initialization'!
@@ -262,16 +309,323 @@
 initialize
 
     super initialize.
-    elements := SortedCollection new.
+    elements := ParseTreeIndex new.
     lastVariableElements := Dictionary new.
 
     "Created: / 14-02-2010 / 13:08:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 25-06-2010 / 13:04:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified: / 21-08-2011 / 09:37:35 / cg"
+    "Modified: / 16-02-2012 / 09:59:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !SyntaxHighlighter2 methodsFor:'parsing-expressions'!
 
+_binaryExpressionFor:receiverArg
+    "parse a binary-expression; return a node-tree, nil or #Error"
+
+    |receiver expr arg sel pos1 pos2 lno|
+
+    receiver := receiverArg.
+    (receiver == #Error) ifTrue:[^ #Error].
+
+    "special kludge: since Scanner cannot know if -digit is a binary
+     expression or a negative constant, handle cases here"
+
+    [(tokenType == #BinaryOperator)
+     or:[(tokenType == $|)
+     or:[(tokenType == $^ and:[parserFlags allowCaretAsBinop])
+	 or:[((tokenType == #Integer) or:[tokenType == #Float])
+	     and:[tokenValue < 0]]]]
+    ] whileTrue:[
+	"/ kludge alarm: in a function-call argList, #, is not a binarySelector
+	inFunctionCallArgument == true ifTrue:[
+	    ((tokenType == #BinaryOperator) and:[tokenName = ',']) ifTrue:[
+		^ receiver
+	    ].
+	].
+
+	pos1 := tokenPosition.
+	lno := tokenLineNr.
+
+	"/ kludge alarm: bar, caret and minus are not scanned as binop
+	(tokenType == $|) ifTrue:[
+	    sel := '|'.
+	    sel := self selectorCheck:sel for:receiver position:tokenPosition to:tokenPosition.
+	    self nextToken.
+	] ifFalse:[
+	    (tokenType == $^) ifTrue:[
+		sel := '^'.
+		sel := self selectorCheck:sel for:receiver position:tokenPosition to:tokenPosition.
+		self nextToken.
+	    ] ifFalse:[
+		(tokenType == #BinaryOperator) ifTrue:[
+		    sel := tokenName.
+		    sel := self selectorCheck:sel for:receiver position:tokenPosition to:(tokenPosition + tokenName size - 1).
+		    self nextToken
+		] ifFalse:[
+		    sel := '-'.
+		    token := tokenValue := tokenValue negated.
+		    tokenPosition := tokenPosition + 1. "/ to skip the sign
+		]
+	    ].
+	].
+
+	pos2 := pos1 + sel size - 1.
+	self markSelector:sel from:pos1 to:pos2 receiverNode:receiver.
+	lastSelectorElement := nil.
+
+	arg := self unaryExpression.
+	(arg == #Error) ifTrue:[^ #Error].
+
+	expr := BinaryNode receiver:receiver selector:sel arg:arg fold:foldConstants.
+	expr isErrorNode ifTrue:[
+	    self parseError:(expr errorString) position:pos1 to:tokenPosition.
+	    errorFlag := false. "ok, user wants it - so he'll get it"
+	    expr := BinaryNode receiver:receiver selector:sel arg:arg fold:nil.
+	].
+	expr lineNumber:lno.
+	expr selectorPosition:pos1.
+
+	self checkPlausibilityOf:expr from:pos1 to:pos2.
+	parseForCode ifFalse:[
+	    self rememberSelectorUsed:sel receiver:receiver
+	].
+	receiver := expr.   "/ for next message
+    ].
+    ^ receiver
+
+    "Modified: / 09-01-1998 / 19:05:18 / stefan"
+    "Modified: / 14-02-2010 / 17:54:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 19-01-2012 / 10:46:49 / cg"
+    "Created: / 16-02-2012 / 21:54:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+_keywordExpressionFor:receiverArg
+    "parse a keyword-expression; return a node-tree, nil or #Error.
+
+     keywordExpression ::= binaryexpression
+			   | { KEYWORD-PART binaryExpression }
+    "
+
+    |expr receiver sel arg args posR1 posR2 pos1 pos2 lno positions constVal|
+
+    receiver := receiverArg.
+    posR1 := tokenPosition.
+    (tokenType == #Keyword) ifFalse:[^ receiver].
+
+    pos1 := posR2 := tokenPosition.
+    pos2 := tokenPosition + tokenName size - 1.
+    positions := OrderedCollection with:(pos1 to:pos2).
+    sel := tokenName.
+    lno := tokenLineNr.
+    self nextToken.
+    arg := self binaryExpression.
+    (arg == #Error) ifTrue:[^ #Error].
+    args := Array with:arg.
+    [tokenType == #Keyword] whileTrue:[
+	sel := sel , tokenName.
+	pos2 := tokenPosition + tokenName size - 1.
+	positions add:(tokenPosition to:pos2).
+	self nextToken.
+	arg := self binaryExpression.
+	(arg == #Error) ifTrue:[^ #Error].
+	args := args copyWith:arg.
+    ].
+
+    positions do:[:p |
+	self markSelector:sel from:p start to:p stop receiverNode:receiver.
+    ].
+    lastSelectorElement := nil.
+    sel := self selectorCheck:sel for:receiver positions:positions.
+
+    ignoreWarnings ifFalse:[
+	(Class definitionSelectors includes:sel) ifTrue:[
+	    (receiver isVariable and:[receiver isUndeclared]) ifTrue:[
+		"this is not an error - the undefined class may be loaded after this code!!"
+		self warning:('as yet undefined superclass: ' , receiver name) position:pos1 to:pos2.
+	    ].
+	].
+    ].
+
+    expr := MessageNode receiver:receiver selector:sel args:args fold:foldConstants.
+    expr isErrorNode ifTrue:[
+	self parseError:(expr errorString) position:pos1 to:pos2.
+	errorFlag := false. "ok, user wants it - so he'll get it"
+	expr := MessageNode receiver:receiver selector:sel args:args fold:nil.
+    ].
+    expr lineNumber:lno.
+    self checkPlausibilityOf:expr from:pos1 to:pos2.
+    parseForCode ifFalse:[
+	self rememberSelectorUsed:sel receiver:receiver
+    ].
+
+"/        (contextToEvaluateIn isNil and:[selfValue isNil]) ifTrue:[    "/ do not check this for doits
+"/            receiver isSuper ifTrue:[
+"/                sel ~= selector ifTrue:[
+"/                    self warnCommonMistake:'possible bad super message (selector should be same as in current method) ?'
+"/                                  position:posR1 to:posR2-1
+"/                ].
+"/            ].
+"/        ].
+"/
+
+    (sel = #ifTrue: or:[sel = #ifFalse: or:[sel = #ifTrue:ifFalse: or:[sel = #ifFalse:ifTrue:]]]) ifTrue:[
+	(expr receiver withConstantValueDo:[:val | constVal := val]) ifTrue:[
+	    |indexOfArgNotExecuted|
+
+	    "/ receiver evaluates to a constant
+	    constVal == true ifTrue:[
+		(sel startsWith: #ifFalse:) ifTrue:[
+		    indexOfArgNotExecuted := 1.
+		] ifFalse:[
+		    indexOfArgNotExecuted := 2.
+		]
+	    ].
+	    constVal == false ifTrue:[
+		(sel startsWith: #ifTrue:) ifTrue:[
+		    indexOfArgNotExecuted := 1.
+		] ifFalse:[
+		    indexOfArgNotExecuted := 2.
+		]
+	    ].
+	    indexOfArgNotExecuted == 2 ifTrue:[
+		args size == 1 ifTrue:[ indexOfArgNotExecuted := nil]
+	    ].
+
+	    indexOfArgNotExecuted notNil ifTrue:[
+		|argIsNotExecuted|
+
+		"/ self warning:'receiver is constant; arg',indexOfArgNotExecuted printString,' is never executed' position:pos1 to:tokenPosition.
+		argIsNotExecuted := expr args at:indexOfArgNotExecuted.
+		argIsNotExecuted isBlockNode ifTrue:[
+		    self markCommentFrom:argIsNotExecuted startPosition to:argIsNotExecuted endPosition.
+		].
+	    ].
+	].
+    ].
+
+    (ignoreErrors or:[ignoreWarnings]) ifFalse:[
+	(sel = #and: or:[sel = #or:]) ifTrue:[
+	    expr arg1 isBlock ifFalse:[
+		(expr arg1 isVariable
+		and:[ (expr arg1 name asLowercase includesString:'block')]) ifFalse:[
+		    self warnCommonMistake:'(possible common mistake) missing block brackets ?'
+			      position:pos2+1 to:tokenPosition-1
+		]
+	    ].
+	    ^ expr.
+	].
+
+	(sel = #whileTrue: or:[sel = #whileFalse:]) ifTrue:[
+	    expr receiver isBlock ifFalse:[
+		(expr receiver isVariable
+		and:[ (expr receiver name asLowercase includesString:'block')]) ifFalse:[
+		    self warnCommonMistake:'(possible common mistake) missing block brackets ?'
+			      position:pos1 to:pos2
+		]
+	    ].
+	    ^ expr.
+	].
+
+	(sel = #ifTrue: or:[sel = #ifFalse:]) ifTrue:[
+	    expr receiver isMessage ifTrue:[
+		(expr receiver selector = #whileTrue or:[expr receiver selector = #whileFalse]) ifTrue:[
+		    self warnCommonMistake:'strange receiver expression'
+			      position:pos1 to:pos2
+		].
+	    ].
+	    ^ expr
+	].
+    ].
+
+    ^ expr.
+
+    "Modified: / 14-02-2010 / 17:58:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 19-01-2012 / 10:47:01 / cg"
+    "Created: / 16-02-2012 / 21:54:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+_unaryExpressionFor:receiverArg
+    "parse a unary-expression; return a node-tree, nil or #Error"
+
+    |receiver expr sel pos pos2 lNr arguments|
+
+    receiver := receiverArg.
+    (receiver == #Error) ifTrue:[^ #Error].
+
+    [ self isValidUnarySelector:tokenType ] whileTrue:[
+	pos := tokenPosition.
+	pos2 := pos + tokenName size - 1.
+	lNr := tokenLineNr.
+	sel := tokenName.
+
+	self markSelector:sel from:pos to:pos2 receiverNode:receiver.
+	lastSelectorElement := nil.
+
+	self nextToken.
+	tokenType == $( ifTrue:[
+	    parserFlags allowSqueakExtensions == true ifTrue:[
+		"/ croquet/squeak extension - c/java-style arguments
+		arguments := self functionCallArgList.
+		"/ synthetic selector: foo[:[with:[with:[...]]]]
+		arguments notEmpty ifTrue:[
+		    sel := sel , ':'.
+		    arguments size - 1 timesRepeat:[ sel := sel , 'with:' ].
+		].
+		sel := self selectorCheck:sel for:receiver position:pos to:pos2.
+		expr := MessageNode receiver:receiver selector:sel args:arguments fold:foldConstants.
+		expr isErrorNode ifTrue:[
+		    self parseError:(expr errorString) position:pos to:pos2.
+		    errorFlag := false. "ok, user wants it - so he'll get it"
+		    expr := MessageNode receiver:receiver selector:sel args:arguments fold:nil.
+		].
+		expr lineNumber:lNr.
+		self checkPlausibilityOf:expr from:pos to:pos2.
+		parseForCode ifFalse:[
+		    self rememberSelectorUsed:sel receiver:receiver
+		].
+		^ expr.
+	    ].
+	].
+
+	sel := self selectorCheck:sel for:receiver position:pos to:pos2.
+	expr := UnaryNode receiver:receiver selector:sel fold:foldConstants.
+	expr isErrorNode ifTrue:[
+	    self warning:(expr errorString , '.\\If you proceed, that error will happen at runtime.') withCRs position:pos to:pos2.
+	    errorFlag := false. "ok, user wants it - so he'll get it"
+	    expr := UnaryNode receiver:receiver selector:sel fold:nil.
+	].
+	expr lineNumber:lNr.
+
+	self checkPlausibilityOf:expr from:pos to:pos2.
+	parseForCode ifFalse:[
+	    self rememberSelectorUsed:sel receiver:receiver
+	].
+
+	receiver := expr.   "/ for next message
+    ].
+    ^ receiver
+
+    "Modified: / 14-02-2010 / 17:56:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 19-01-2012 / 10:47:37 / cg"
+    "Created: / 16-02-2012 / 21:54:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+binaryExpression
+    | node savedLastSelectorElement |
+
+    savedLastSelectorElement := lastSelectorElement.
+    lastSelectorElement := nil.
+    node := super binaryExpression.
+    (lastSelectorElement notNil and:[node ~~ #Error and:[node isMessage]]) ifTrue:[
+	lastSelectorElement node parent: node.
+    ].
+    lastSelectorElement := savedLastSelectorElement.
+    ^node
+
+    "Modified: / 19-01-2000 / 16:22:16 / cg"
+    "Created: / 16-02-2012 / 21:56:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 binaryExpressionFor:receiverArg
     "parse a binary-expression; return a node-tree, nil or #Error"
 
@@ -349,132 +703,22 @@
 !
 
 expression
-    "parse a cascade-expression; return a node-tree, nil or #Error.
-
-     expression ::= keywordExpression
-                    | keywordExpression cascade
-
-     cascade ::= ';' expressionSendPart
-                 | cascade ';' expressionSendPart
-
-     expressionSendPart ::= { KEYWORD binaryExpression }
-                            | BINARYOPERATOR unaryExpression
-                            | IDENTIFIER
-    "
+    | node savedLastSelectorElement |
 
-    |receiver arg sel args pos pos2 lno tokenEnd realReceiver positions|
-
-    pos := tokenPosition.
-    receiver := self keywordExpression.
-    (receiver == #Error) ifTrue:[^ #Error].
-    (tokenType == $;) ifTrue:[
-        receiver isMessage ifFalse:[
-            self syntaxError:'left side of cascade must be a message expression'
-                    position:pos to:tokenPosition.
-            realReceiver := receiver. "/ only to allow continuing.
-        ] ifTrue:[
-            realReceiver := receiver receiver.
+    savedLastSelectorElement := lastSelectorElement.
+    lastSelectorElement := nil.
+    node := super expression.
+    ((node ~~ #Error) and:[node isMessage]) ifTrue:[
+        [ lastSelectorElement notNil ] whileTrue:[
+            lastSelectorElement node parent: node.
+            lastSelectorElement := lastSelectorElement prev.
         ].
-        [tokenType == $;] whileTrue:[
-            self nextToken.
-            (tokenType == #Identifier) ifTrue:[
-                tokenEnd := tokenPosition + tokenName size - 1.
-                self markSelector:tokenName from:tokenPosition to:tokenEnd receiverNode:realReceiver.
-                sel := tokenName.
-                sel := self selectorCheck:tokenName for:realReceiver position:tokenPosition to:tokenEnd.
-                receiver := CascadeNode receiver:receiver selector:sel.
-                receiver lineNumber:tokenLineNr.
-                self nextToken.
-            ] ifFalse:[
-                (tokenType == #BinaryOperator) ifTrue:[
-                    tokenEnd := tokenPosition + tokenName size - 1.
-                    self markSelector:tokenName from:tokenPosition to:tokenEnd receiverNode:realReceiver.
-                    lastSelectorElement := nil.
-                    sel := tokenName.
-                    sel := self selectorCheck:tokenName for:realReceiver position:tokenPosition to:tokenEnd.
-                    lno := tokenLineNr. 
-                    self nextToken.
-                    arg := self unaryExpression.
-                    (arg == #Error) ifTrue:[^ #Error].
-                    receiver := CascadeNode receiver:receiver selector:sel arg:arg.
-                    receiver lineNumber:lno.
-                ] ifFalse:[
-                    (tokenType == #Keyword) ifTrue:[
-                        tokenEnd := tokenPosition + tokenName size - 1.
-                        positions := OrderedCollection with:(tokenPosition to:tokenEnd).
-                        pos := tokenPosition.
-                        pos2 := tokenEnd.
-                        lno := tokenLineNr. 
-                        sel := tokenName.
-                        self nextToken.
-                        arg := self binaryExpression.
-                        (arg == #Error) ifTrue:[^ #Error].
-                        args := Array with:arg.
-                        [tokenType == #Keyword] whileTrue:[
-                            tokenEnd := tokenPosition + tokenName size - 1.
-                            positions add:(tokenPosition to:tokenEnd).
-                            sel := sel , tokenName.
-                            self nextToken.
-                            arg := self binaryExpression.
-                            (arg == #Error) ifTrue:[^ #Error].
-                            args := args copyWith:arg.
-                            pos2 := tokenEnd
-                        ].
-                        positions do:[:p |
-                            self markSelector:sel from:p start to:p stop receiverNode:realReceiver.
-                        ].
-                        lastSelectorElement := nil.                                
-
-                        sel := self selectorCheck:sel for:realReceiver position:pos to:pos2.
-
-                        receiver := CascadeNode receiver:receiver selector:sel args:args.
-                        receiver lineNumber:lno.
-                    ] ifFalse:[
-                        (tokenType == #Error) ifTrue:[^ #Error].
-                        self syntaxError:('invalid cascade; ' , tokenType printString , ' unexpected')
-                                position:tokenPosition to:source position.
-                        ^ #Error
-                    ]
-                ]
-            ]
-        ].
-
-        "obscure (unspecified ?) if selector follows; Question:
-
-        is
-                'expr sel1; sel2 sel3'
-
-        to be parsed as: 
-                (t := expr.
-                 t sel1.
-                 t sel2) sel3
-
-         or:
-                (t := expr.
-                 t sel1.
-                 t sel2 sel3)
-        "
-        ((tokenType == #Identifier) 
-         or:[(tokenType == #BinaryOperator)
-             or:[tokenType == #Keyword]]) ifTrue:[
-            self syntaxError:'ambigous cascade - please group using (...)'
-                    position:tokenPosition to:source position.
-            ^ #Error
-"/            self warning: "syntaxError:" 'possibly ambigous cascade - please group using (...)'
-"/                    position:tokenPosition to:source position - 1.
-"/            tokenType == #Identifier ifTrue:[
-"/                ^ self unaryExpressionFor:receiver
-"/            ].
-"/            tokenType == #BinaryOperator ifTrue:[
-"/                ^ self binaryExpressionFor:receiver
-"/            ].
-"/            ^ self keywordExpressionFor:receiver
-        ]
     ].
-    ^ receiver
+    lastSelectorElement := savedLastSelectorElement.
+    ^node
 
     "Modified: / 19-01-2000 / 16:22:16 / cg"
-    "Modified: / 14-02-2010 / 17:58:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 16-02-2012 / 23:39:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 keywordExpressionFor:receiverArg
@@ -621,64 +865,112 @@
 unaryExpressionFor:receiverArg
     "parse a unary-expression; return a node-tree, nil or #Error"
 
-    |receiver expr sel pos pos2 lNr arguments|
+    |receiver expr sel pos pos2 lNr arguments savedLastSelectorElement|
 
+    savedLastSelectorElement := lastSelectorElement.
     receiver := receiverArg.
     (receiver == #Error) ifTrue:[^ #Error].
 
     [ self isValidUnarySelector:tokenType ] whileTrue:[
-        pos := tokenPosition.
-        pos2 := pos + tokenName size - 1.
-        lNr := tokenLineNr.
-        sel := tokenName.
+	pos := tokenPosition.
+	pos2 := pos + tokenName size - 1.
+	lNr := tokenLineNr.
+	sel := tokenName.
 
-        self markSelector:sel from:pos to:pos2 receiverNode:receiver.
-        lastSelectorElement := nil.
+	lastSelectorElement := nil.
+	self markSelector:sel from:pos to:pos2 receiverNode:receiver.
 
-        self nextToken.
-        tokenType == $( ifTrue:[
-            parserFlags allowSqueakExtensions == true ifTrue:[
-                "/ croquet/squeak extension - c/java-style arguments
-                arguments := self functionCallArgList.
-                "/ synthetic selector: foo[:[with:[with:[...]]]]
-                arguments notEmpty ifTrue:[
-                    sel := sel , ':'.
-                    arguments size - 1 timesRepeat:[ sel := sel , 'with:' ].
-                ].
-                sel := self selectorCheck:sel for:receiver position:pos to:pos2.
-                expr := MessageNode receiver:receiver selector:sel args:arguments fold:foldConstants.
-                expr isErrorNode ifTrue:[
-                    self parseError:(expr errorString) position:pos to:pos2.
-                    errorFlag := false. "ok, user wants it - so he'll get it"
-                    expr := MessageNode receiver:receiver selector:sel args:arguments fold:nil.
-                ].
-                expr lineNumber:lNr.
-                self checkPlausibilityOf:expr from:pos to:pos2.
-                ^ expr.
-            ].
-        ].
+	self nextToken.
+	tokenType == $( ifTrue:[
+	    parserFlags allowSqueakExtensions == true ifTrue:[
+		"/ croquet/squeak extension - c/java-style arguments
+		arguments := self functionCallArgList.
+		"/ synthetic selector: foo[:[with:[with:[...]]]]
+		arguments notEmpty ifTrue:[
+		    sel := sel , ':'.
+		    arguments size - 1 timesRepeat:[ sel := sel , 'with:' ].
+		].
+		sel := self selectorCheck:sel for:receiver position:pos to:pos2.
+		expr := MessageNode receiver:receiver selector:sel args:arguments fold:foldConstants.
+		expr isErrorNode ifTrue:[
+		    self parseError:(expr errorString) position:pos to:pos2.
+		    errorFlag := false. "ok, user wants it - so he'll get it"
+		    expr := MessageNode receiver:receiver selector:sel args:arguments fold:nil.
+		].
+		lastSelectorElement node parent: expr.
+		expr lineNumber:lNr.
+		self checkPlausibilityOf:expr from:pos to:pos2.
+		parseForCode ifFalse:[
+		    self rememberSelectorUsed:sel receiver:receiver
+		].
+		^ expr.
+	    ].
+	].
 
-        sel := self selectorCheck:sel for:receiver position:pos to:pos2.
-        expr := UnaryNode receiver:receiver selector:sel fold:foldConstants.
-        expr isErrorNode ifTrue:[
-            self warning:(expr errorString , '.\\If you proceed, that error will happen at runtime.') withCRs position:pos to:pos2.
-            errorFlag := false. "ok, user wants it - so he'll get it"
-            expr := UnaryNode receiver:receiver selector:sel fold:nil.
-        ].
-        expr lineNumber:lNr.
+	sel := self selectorCheck:sel for:receiver position:pos to:pos2.
+	expr := UnaryNode receiver:receiver selector:sel fold:foldConstants.
+	expr isErrorNode ifTrue:[
+	    self warning:(expr errorString , '.\\If you proceed, that error will happen at runtime.') withCRs position:pos to:pos2.
+	    errorFlag := false. "ok, user wants it - so he'll get it"
+	    expr := UnaryNode receiver:receiver selector:sel fold:nil.
+	].
+	expr lineNumber:lNr.
+	lastSelectorElement node parent: expr.
 
-        self checkPlausibilityOf:expr from:pos to:pos2.
+	self checkPlausibilityOf:expr from:pos to:pos2.
+	parseForCode ifFalse:[
+	    self rememberSelectorUsed:sel receiver:receiver
+	].
 
-        receiver := expr.   "/ for next message
+	receiver := expr.   "/ for next message
     ].
+    lastSelectorElement := savedLastSelectorElement.
     ^ receiver
 
-    "Modified: / 14-02-2010 / 17:56:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified: / 19-01-2012 / 10:47:37 / cg"
+    "Created: / 16-02-2012 / 23:50:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+variable
+    | node |
+
+    ignoreBadIdentifier := classToCompileFor isNil.
+    node := super variable.
+    ignoreBadIdentifier := false.
+    node isVariable ifTrue:[
+	| el prevEl |
+
+	el := elements newElementFor: node.
+	prevEl := lastVariableElements at:node name ifAbsent:[nil].
+	prevEl notNil ifTrue:[prevEl next:el].
+	lastVariableElements at:node name put:el.
+	elements add: el.
+    ].
+    ^node
+
+    "Modified: / 19-01-2000 / 16:22:16 / cg"
+    "Created: / 16-02-2012 / 22:21:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !SyntaxHighlighter2 methodsFor:'syntax detection'!
 
+markArgumentIdentifierFrom:pos1 to:pos2
+    | node el prevEl |
+
+    super markArgumentIdentifierFrom:pos1 to:pos2.
+    node := VariableNode methodArgumentNamed:(sourceText string copyFrom: pos1 to: pos2).
+    node startPosition: pos1 endPosition: pos2.
+    el := elements newElementFor: node.
+    prevEl := lastVariableElements at:node name ifAbsent:[nil].
+    prevEl notNil ifTrue:[prevEl next:el].
+    lastVariableElements at:node name put:el.
+    elements add: el.
+
+    "Created: / 24-07-2010 / 09:25:12 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 21-08-2011 / 09:27:26 / cg"
+    "Modified: / 16-02-2012 / 22:34:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 markAssignedVariable:v from:pos to:endPos
     super markAssignedVariable:v from:pos to:endPos.
     (v type == #GlobalVariable) ifTrue:[^self].
@@ -686,6 +978,13 @@
     self rememberVariableElementFor:v name type:v type from:pos to:endPos assigned:true
 !
 
+markBadIdentifierFrom:pos1 to:pos2
+
+    super markBadIdentifierFrom:pos1 to:pos2
+
+    "Created: / 17-03-2012 / 19:02:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 markGlobalClassIdentifierFrom:pos1 to:pos2
 
     | name env cls |
@@ -709,8 +1008,19 @@
 !
 
 markLocalIdentifierFrom:pos1 to:pos2
+    | node el prevEl |
+
     super markLocalIdentifierFrom:pos1 to:pos2.
-    self rememberVariableElementFor:tokenName type:#MethodVariable from:pos1 to:pos2 assigned:false
+    node := VariableNode methodLocalNamed:(sourceText string copyFrom: pos1 to: pos2).
+    node startPosition: pos1 endPosition: pos2.
+    el := elements newElementFor: node.
+    prevEl := lastVariableElements at:node name ifAbsent:[nil].
+    prevEl notNil ifTrue:[prevEl next:el].
+    lastVariableElements at:node name put:el.
+    elements add: el.
+
+    "Modified: / 21-08-2011 / 09:27:26 / cg"
+    "Created: / 16-02-2012 / 22:36:41 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 markMethodArgumentIdentifierFrom:pos1 to:pos2
@@ -725,18 +1035,35 @@
 
     | element selectorSymbol |
 
-    super markSelector:selectorString from:pos1 to:pos2 receiverNode:aReceiverNode.
+    "Special hack for Java class references - I would like to have them
+     marked specially (and not as an error when the class is not yet loaded -
+     the code is correct as JavaClassAccessor loads it lazily"
+    (aReceiverNode isJavaPackageReference) ifTrue:[
+	self
+	    markFrom:pos1 to:pos2
+	    withEmphasis:preferences globalClassIdentifierEmphasis
+	    color: preferences globalClassIdentifierColor
+    ] ifFalse:[
+	super markSelector:selectorString from:pos1 to:pos2 receiverNode:aReceiverNode.
+    ].
+
     "don't create symbols for partial typed selectors"
     selectorSymbol := selectorString asSymbolIfInterned.
 
-    element := SyntaxElement from: pos1 to: pos2 type: #selector value: (selectorSymbol ? selectorString).
-    lastSelectorElement ifNotNil:[lastSelectorElement next: element].
+    element := elements newElementFor: (SelectorNode value: selectorString from: pos1 to: pos2).
+
+    (lastSelectorElement notNil "and:[lastSelectorElement value = selectorString]") ifTrue:[
+	lastSelectorElement next: element.
+    ].
     elements add: element.
-    lastSelectorElement := element.
+    lastSelectorElement := "(self isValidUnarySelector:tokenType)"false
+				ifTrue:[nil]
+				ifFalse:[element].
 
     "Created: / 14-02-2010 / 17:40:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified: / 14-02-2010 / 19:24:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified (format): / 21-08-2011 / 09:18:21 / cg"
+    "Modified: / 19-04-2012 / 09:53:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 markSelfFrom:pos1 to:pos2
@@ -748,12 +1075,12 @@
 
 markUnknownIdentifierFrom:pos1 to:pos2
 
-    classToCompileFor notNil 
-        ifTrue:[super markUnknownIdentifierFrom:pos1 to:pos2]
-        ifFalse:[self markLocalIdentifierFrom: pos1 to: pos2].
+    ignoreBadIdentifier == true ifTrue:[ ^ self ].
 
-    "Created: / 24-07-2010 / 09:51:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 02-08-2011 / 09:35:02 / cg"
+    super markUnknownIdentifierFrom:pos1 to:pos2
+
+    "Created: / 31.3.1998 / 19:09:26 / cg"
+    "Modified: / 31.3.1998 / 19:10:30 / cg"
 !
 
 markVariable:v from:pos1 to:pos2 assigned:assigned
@@ -794,14 +1121,14 @@
 !SyntaxHighlighter2 class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libtool/SyntaxHighlighter2.st,v 1.18 2013-08-10 11:10:24 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libtool/SyntaxHighlighter2.st,v 1.19 2014-02-05 18:59:09 cg Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libtool/SyntaxHighlighter2.st,v 1.18 2013-08-10 11:10:24 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libtool/SyntaxHighlighter2.st,v 1.19 2014-02-05 18:59:09 cg Exp $'
 !
 
 version_SVN
-    ^ '$Id: SyntaxHighlighter2.st,v 1.18 2013-08-10 11:10:24 stefan Exp $'
+    ^ '$Id: SyntaxHighlighter2.st,v 1.19 2014-02-05 18:59:09 cg Exp $'
 ! !