<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>