<body><div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000">
                                        Hi all!<div><br></div><div>If nobody speaks up until tomorrow, I would like to move this to Trunk. ^___^ Sorry for the short notice.</div><div><br></div><div>Even if you agree with the basic mechanism, please feel free to suggest names for the pragma in the methods that direct pragma parsing. I chose <pragmaParser> for now.</div><div><br></div><div>Best,</div><div>Marcel</div><div class="mb_sig"></div><blockquote class="history_container" type="cite" style="border-left-style:solid;border-width:1px; margin-top:20px; margin-left:0px;padding-left:10px;">
                        <p style="color: #AAAAAA; margin-top: 10px;">Am 12.06.2020 09:45:02 schrieb commits@source.squeak.org <commits@source.squeak.org>:</p><div style="font-family:Arial,Helvetica,sans-serif">A new version of Compiler was added to project The Inbox:<br>http://source.squeak.org/inbox/Compiler-mt.436.mcz<br><br>==================== Summary ====================<br><br>Name: Compiler-mt.436<br>Author: mt<br>Time: 12 June 2020, 9:44:51.105703 am<br>UUID: 2f141bd8-8dd0-0d4a-a053-e9e006c7dde7<br>Ancestors: Compiler-mt.435<br><br>Adds a (extension) method-based hook to install custom pragma-parsing methods. Use it to move FFI-specific pragma-parsing, i.e. <apicall: ...=""> and <cdecl: ...="">, into FFI packages.<br><br>Redirects parsing of <primitive: ...=""> to document the hook.<br><br>=============== Diff against Compiler-mt.435 ===============<br><br>Item was removed:<br>- ----- Method: Parser>>externalFunctionDeclaration (in category 'primitives') -----<br>- externalFunctionDeclaration<br>-  "Parse the function declaration for a call to an external library."<br>-        | descriptorClass callType modifier retType externalName args argType module fn |<br>-    descriptorClass := cue environment<br>-           valueOf: #ExternalFunction <br>-          ifAbsent: [^ false].<br>-         callType := descriptorClass callingConventionFor: here.<br>-      callType == nil ifTrue:[^false].<br>-     [modifier := descriptorClass callingConventionModifierFor: token.<br>-     modifier notNil] whileTrue:<br>-                 [self advance.<br>-                callType := callType bitOr: modifier].<br>-      "Parse return type"<br>-        self advance.<br>-        retType := self externalType: descriptorClass.<br>-       retType == nil ifTrue:[^self expected:'return type'].<br>-        "Parse function name or index"<br>-     externalName := here.<br>-        (self match: #string) <br>-               ifTrue:[externalName := externalName asSymbol]<br>-               ifFalse:[(self match:#number) ifFalse:[^self expected:'function name or index']].<br>-    (self match: #leftParenthesis) ifFalse:[^self expected:'argument list'].<br>-     args := WriteStream on: Array new.<br>-   [self match: #rightParenthesis] whileFalse:[<br>-                 argType := self externalType: descriptorClass.<br>-               argType == nil ifTrue:[^self expected:'argument'].<br>-           argType isVoid & argType isPointerType not ifFalse:[args nextPut: argType]].<br>-     (self matchToken: 'module:') ifTrue:[<br>-                module := here.<br>-              (self match: #string) ifFalse:[^self expected: 'String'].<br>-            module := module asSymbol].<br>-  Smalltalk at: #ExternalLibraryFunction ifPresent:[:xfn|<br>-              fn := xfn name: externalName <br>-                                module: module <br>-                              callType: callType<br>-                           returnType: retType<br>-                          argumentTypes: args contents.<br>-                encoder litIndex: fn.<br>-                fn beWritableObject. "Undo the read-only setting in litIndex:"].<br>-   (self matchToken: 'error:')<br>-          ifTrue:<br>-                      [| errorCodeVariable |<br>-                        errorCodeVariable := here.<br>-                  (hereType == #string<br>-                          or: [hereType == #word]) ifFalse:[^self expected: 'error code (a variable or string)'].<br>-                      self advance.<br>-                        self addPragma: (Pragma keyword: #primitive:error: arguments: (Array with: 120 with: errorCodeVariable)).<br>-                    fn ifNotNil: [fn setErrorCodeName: errorCodeVariable]]<br>-              ifFalse:<br>-                     [self addPragma: (Pragma keyword: #primitive: arguments: #(120))].<br>-   ^true!<br><br>Item was removed:<br>- ----- Method: Parser>>externalType: (in category 'primitives') -----<br>- externalType: descriptorClass<br>-   "Parse and return an external type"<br>-        | xType typeName |<br>-   typeName := here. "Note that pointer token is not yet parsed!!"<br>-    (xType := descriptorClass typeNamed: typeName)<br>-               ifNil: [<br>-                     "Raise an error if user is there"<br>-                  self interactive ifTrue: [^nil].<br>-                     "otherwise go over it silently -- use an unknown struct type"<br>-                      xType := descriptorClass newTypeNamed: here].<br>-        self advance.<br>-        ^ (self matchToken: #*)<br>-              ifTrue:[xType asPointerType]<br>-                 ifFalse:[(self matchToken: #**)<br>-                      ifTrue: [xType asPointerToPointerType]<br>-                       ifFalse: [xType]]!<br><br>Item was changed:<br>  ----- Method: Parser>>pragmaStatement (in category 'pragmas') -----<br>  pragmaStatement<br>+      "Read a single pragma statement. Dispatch to the first available pragma parser using the current token as a simple getter to be called on self. If no pragma parser can be found, parse it as usual in the keywords form.<br>-       "Read a single pragma statement. Parse all generic pragmas in the form of: <key1: val1="" key2:="" val2="" ...=""> and remember them, including primitives."<br>          <br>+     Note that custom pragma parsers need to fulfill two requirements:<br>+            (1) method selector must match the current token as simple getter,<br>+                           e.g., <apicall: ...=""> matches #apicall or <primitive: ...=""> matches #primitive<br>+           (2) method must declare <pragmaparser> to be called.<br>+   This is for the protection of the parser's (message) namespace."<br>+        <br>+     | parserSelector parserMethod |<br>-      | selector arguments words index keyword |<br>    (hereType = #keyword or: [ hereType = #word or: [ hereType = #binary ] ])<br>             ifFalse: [  ^ self expected: 'pragma declaration' ].<br>  <br>+     (self class includesSelector: (parserSelector := here asSimpleGetter)) ifTrue: [<br>+             ((parserMethod := self class compiledMethodAt: parserSelector) pragmas<br>+                       anySatisfy: [:pragma | pragma keyword == #pragmaParser])<br>+                             ifTrue: [^ self executeMethod: parserMethod]].<br>-       " This is a ugly hack into the compiler of the FFI package. FFI should be changed to use propre pragmas that can be parsed with the code here. "<br>-   (here = #apicall: or: [ here = #cdecl: ])<br>-            ifTrue: [ ^ self externalFunctionDeclaration ].<br>  <br>+  ^ self pragmaStatementKeywords!<br>-      selector := String new.<br>-      arguments := OrderedCollection new.<br>-  words := OrderedCollection new.<br>-      [ hereType = #keyword or: [ (hereType = #word or: [ hereType = #binary ]) and: [ selector isEmpty ] ] ] whileTrue: [<br>-                 index := self startOfNextToken + requestorOffset.<br>-            selector := selector , self advance.<br>-                 words add: (index to: self endOfLastToken + requestorOffset).<br>-                (selector last = $: or: [ selector first isLetter not ])<br>-                     ifTrue: [ arguments add: (self pragmaLiteral: selector) ] ].<br>-         selector numArgs ~= arguments size<br>-           ifTrue: [ ^ self expected: 'pragma argument' ].<br>-      (Symbol hasInterned: selector <br>-               ifTrue: [ :value | keyword := value]) <br>-               ifFalse: [ <br>-                  keyword := self <br>-                             correctSelector: selector wordIntervals: words<br>-                               exprInterval: (words first first to: words last last)<br>-                                ifAbort: [ ^ self fail ] ].<br>-  self addPragma: (Pragma keyword: keyword arguments: arguments asArray).<br>-      ^ true!<br><br>Item was added:<br>+ ----- Method: Parser>>pragmaStatementKeywords (in category 'pragmas') -----<br>+ pragmaStatementKeywords<br>+   "Read a single pragma statement. Parse all generic pragmas in the form of: <key1: val1="" key2:="" val2="" ...=""> and remember them, including primitives."<br>+         <br>+     | selector arguments words index keyword |<br>+   selector := String new.<br>+      arguments := OrderedCollection new.<br>+  words := OrderedCollection new.<br>+      [ hereType = #keyword or: [ (hereType = #word or: [ hereType = #binary ]) and: [ selector isEmpty ] ] ] whileTrue: [<br>+                 index := self startOfNextToken + requestorOffset.<br>+            selector := selector , self advance.<br>+                 words add: (index to: self endOfLastToken + requestorOffset).<br>+                (selector last = $: or: [ selector first isLetter not ])<br>+                     ifTrue: [ arguments add: (self pragmaLiteral: selector) ] ].<br>+         selector numArgs ~= arguments size<br>+           ifTrue: [ ^ self expected: 'pragma argument' ].<br>+      (Symbol hasInterned: selector <br>+               ifTrue: [ :value | keyword := value]) <br>+               ifFalse: [ <br>+                  keyword := self <br>+                             correctSelector: selector wordIntervals: words<br>+                               exprInterval: (words first first to: words last last)<br>+                                ifAbort: [ ^ self fail ] ].<br>+  self addPragma: (Pragma keyword: keyword arguments: arguments asArray).<br>+      ^ true!<br><br>Item was added:<br>+ ----- Method: Parser>>primitive (in category 'primitives') -----<br>+ primitive<br>+    "Pragmas that encode primitive calls are parsed as normal keyword pragmas. This hook exists so that packages do not break primitive-pragma parsing by accident. Instead, this method needs to be replaced intentionally.<br>+        <br>+     Note that primitive pragmas are special because they will be called back from the parser into the parser. See #pragmaPrimitives.<br>+     <br>+     Examples:<br>+            <primitive: 42=""><br>+           <primitive: 'primitivedirectorycreate'="" module:="" 'fileplugin'=""><br>+            <primitive: 'primitiveregisterexternalfill'="" module:="" 'b2dplugin'="" error:="" errorcode="">"<br>+ <br>+   <pragmaparser><br>+         ^ self pragmaStatementKeywords!<br><br><br></pragmaparser></primitive:></primitive:></primitive:></key1:></pragmaparser></primitive:></apicall:></key1:></primitive:></cdecl:></apicall:></div></blockquote>
                                        </div></body>