Hi,
I was wondering how the type was handle when apicall or cdecl occur. I have read how it is parse by the compiler and don't understand the following: ====================================== Parser>>externalType: descriptorClass "Parse an return an external type" | xType | xType _ descriptorClass atomicTypeNamed: here. xType == nil ifTrue:["Look up from class scope" *here* Symbol hasInterned: here ifTrue:[:sym| *here* xType _ descriptorClass structTypeNamed: sym]]. xType == nil ifTrue:[ "Raise an error if user is there" *here* self interactive ifTrue:[^nil]. "otherwise go over it silently" *here* xType _ descriptorClass forceTypeNamed: here]. self advance. (self matchToken:#*) ifTrue:[^xType asPointerType] ifFalse:[^xType] ============================================= So if somebody can explain it to me thanks :) Math |
Since this is the second time you're posting a question in this area
(which makes me assume that you're actually interested in getting an answer) I'll point you gently to: http://linuxmafia.com/faq/Essays/smart-questions.html Please read it and note in particular the parts about "Be precise and informative about your problem" and "Be explicit about your question". Cheers, - Andreas mathieu wrote: > Hi, > > I was wondering how the type was handle when apicall or cdecl occur. > I have read how it is parse by the compiler and don't understand the > following: > > ====================================== > Parser>>externalType: descriptorClass > "Parse an return an external type" > | xType | > xType _ descriptorClass atomicTypeNamed: here. > xType == nil ifTrue:["Look up from class scope" > *here* Symbol hasInterned: here ifTrue:[:sym| > *here* xType _ descriptorClass structTypeNamed: sym]]. > xType == nil ifTrue:[ > "Raise an error if user is there" > *here* self interactive ifTrue:[^nil]. > "otherwise go over it silently" > *here* xType _ descriptorClass forceTypeNamed: here]. > self advance. > (self matchToken:#*) > ifTrue:[^xType asPointerType] > ifFalse:[^xType] > ============================================= > > So if somebody can explain it to me thanks :) > > Math > > |
Andreas Raab a écrit :
> Since this is the second time you're posting a question in this area > (which makes me assume that you're actually interested in getting an > answer) I'll point you gently to: > > http://linuxmafia.com/faq/Essays/smart-questions.html > > Please read it and note in particular the parts about "Be precise and > informative about your problem" and "Be explicit about your question". ok sorry. So what the ExternalType served for? I don't understand why you have to ask in 2 different way the ExternalType (xType := descriptorClass atomicTypeNamed: here and xType := descriptorClass structTypeNamed: sym)? What the mssage #hasInterned:ifTrue: served for in this case? > Cheers, > - Andreas > > mathieu wrote: >> Hi, >> >> I was wondering how the type was handle when apicall or cdecl occur. >> I have read how it is parse by the compiler and don't understand the >> following: >> >> ====================================== >> Parser>>externalType: descriptorClass >> "Parse an return an external type" >> | xType | >> xType _ descriptorClass atomicTypeNamed: here. >> xType == nil ifTrue:["Look up from class scope" >> *here* Symbol hasInterned: here ifTrue:[:sym| >> *here* xType _ descriptorClass structTypeNamed: sym]]. >> xType == nil ifTrue:[ >> "Raise an error if user is there" >> *here* self interactive ifTrue:[^nil]. >> "otherwise go over it silently" >> *here* xType _ descriptorClass forceTypeNamed: here]. >> self advance. >> (self matchToken:#*) >> ifTrue:[^xType asPointerType] >> ifFalse:[^xType] >> ============================================= >> >> So if somebody can explain it to me thanks :) >> >> Math >> >> > > > |
Le Mercredi 19 Juillet 2006 08:24, mathieu a écrit :
> Andreas Raab a écrit : > > Since this is the second time you're posting a question in this area > > (which makes me assume that you're actually interested in getting an > > answer) I'll point you gently to: > > > > http://linuxmafia.com/faq/Essays/smart-questions.html > > > > Please read it and note in particular the parts about "Be precise and > > informative about your problem" and "Be explicit about your question". > > ok sorry. > > So what the ExternalType served for? > ExternalType is Smalltalk class used to handle external function argument types and function return types. It is necessary to handle automatic conversions from Smalltalk Objects to C Objects et vice et versa. > I don't understand why you have to ask in 2 different way the > ExternalType (xType := descriptorClass atomicTypeNamed: here and xType > This is a list of tests: 1) check if there is an atomic type whose name is here (atomic types are non composed types like float double short long int etc...) 2) if the answer is nil, then here is not an atomic type, try to see if it is the name of a structure type... You must understand that returning nil is a simple way to indicate a failure (a kind of C-style programming). > := descriptorClass structTypeNamed: sym)? > > What the mssage #hasInterned:ifTrue: served for in this case? here is aString (a token parsed by the parser). It should be the name of a known type. If here is a known type, then corresponding symbol (here asSymbol) must already exist in the image. That is exactly what #hasInterned:ifTrue: is cheking: does a Symbol having same characters as here exist in the image, and if true, it will try to set the type to be a structure... Once again, structTypeNamed: will do the job of checking if (here asSymbol) is really the name of an ExternalStructure (most Symbols are not the name of a structure). If not, it will answer nil. If there is no symbol like here, then we are sure that there is currently no such ExternalStructure declared in the Smalltalk image, and it's not even necessary to check if an ExternalStructure does have that name. > > > Cheers, > > - Andreas > > > > mathieu wrote: > >> Hi, > >> > >> I was wondering how the type was handle when apicall or cdecl occur. > >> I have read how it is parse by the compiler and don't understand the > >> following: > >> > >> ====================================== > >> Parser>>externalType: descriptorClass > >> "Parse an return an external type" > >> > >> | xType | > >> > >> xType _ descriptorClass atomicTypeNamed: here. > >> xType == nil ifTrue:["Look up from class scope" > >> *here* Symbol hasInterned: here ifTrue:[:sym| > >> *here* xType _ descriptorClass structTypeNamed: sym]]. > >> xType == nil ifTrue:[ > >> "Raise an error if user is there" > >> *here* self interactive ifTrue:[^nil]. An error is detected; no such named type does exist in the image, neither a known atomic type, nor a known structure type: If compilation isInteractive (that is user did select accept menu in the browser), then it's better to warn the user because he is trying to enter some incorrect code. Answering nil here will be checked at upper level and raise a SyntaxError notified to the user. If not interactive (as for example he is loading code from a file, Monticello or whatever source), it's bad to warn the user for something he is not responsible for. And maybe, the type is not known yet, but is defined further in the file... In this case, force the type to be recognized as a structure (I let you inquire how). > >> "otherwise go over it silently" > >> *here* xType _ descriptorClass forceTypeNamed: here]. > >> self advance. > >> (self matchToken:#*) > >> ifTrue:[^xType asPointerType] > >> ifFalse:[^xType] > >> ============================================= > >> > >> So if somebody can explain it to me thanks :) > >> > >> Math |
In reply to this post by Mathieu SUEN
mathieu wrote:
> I don't understand why you have to ask in 2 different way the > ExternalType (xType := descriptorClass atomicTypeNamed: here and xType > := descriptorClass structTypeNamed: sym)? There is no particular reason that I remember why there isn't a unified interface like #typeNamed:. I think it's probably because this code changed a number of times and I wrote it under pressure and never looked at it again (hey, it works just fine even if it ain't the most pretty code ;-) There are reasons why you'd have to know in other places but the parser really couldn't care less. > What the mssage #hasInterned:ifTrue: served for in this case? Only as an optimization (if there isn't an interned name for the type we don't even need to check). I *vaguely* seem to remember that the structure management used to be a lot more complex than it ultimately ended up being; this might also explain why I'd split the two into the (cheap) atomic test and an (expensive) struct variant. Note that the line saying "self interactive ifTrue:[^nil]" *is* relevant however. What it does is to disable the "forward declaration" of external types that are used in FFI calls. It is required since two ExternalTypes can refer to each other in their methods (e.g., TypeA>>methodA using TypeB and TypeB>>methodB using TypeA) and without this forward declaration feature you'd never be able to load any such classes. The particular line simply disables that when you use an interactive input (browser) to ensure that you do indeed declare the types when you use the parser interactively. Cheers, - Andreas |
In reply to this post by Nicolas Cellier-3
Ok thank a lot nicolas (in fact those ifNil: were boring me)
Now I understand the hasInterned:ifTrue: :). I ask those question because I am adding this to the new compiler. So I have to follow the same structur to get the ExternalType. But it seem to be not really pretty with nil value. Now I am writing the grammar so is the atomicType restrict to bool, void, byte, schar, double, float, sbyte, char, ushort, short, longlong, ulong, ulonglong, long ? 2006/7/19, nicolas cellier <[hidden email]>: Le Mercredi 19 Juillet 2006 08:24, mathieu a écrit : |
In reply to this post by Andreas.Raab
2006/7/19, Andreas Raab <[hidden email]>: mathieu wrote: ok I see. :) Note that the line saying "self interactive ifTrue:[^nil]" *is* relevant ok thanks :) Cheers, |
In reply to this post by Mathieu SUEN
Mathieu SUEN wrote:
> I ask those question because I am adding this to the new compiler. And why didn't you say so before? See ESR's essay where he talks about "describe the goal not the steps". Your questions make a lot more sense when you add just that single sentence for explaining why you're looking at this code at all. > So I have to follow the same structur to get the ExternalType. But it > seem to be not really pretty with nil value. It is a perfectly reasonable thing to do. The compiler is querying for the existence of a type by that name. If there is none, the answer is undefined, an UndefinedObject, e.g., nil. What is not pretty about it? > Now I am writing the grammar so is the atomicType restrict to > > bool, void, byte, schar, double, > float, sbyte, char, ushort, short, > longlong, ulong, ulonglong, long > > ? Bad idea. Don't assume that this is any fixed set of atomic types. In fact, the code has been written the way it is (vectoring through ExternalType instead of hardcoding it in the parser) precisely to allow later extensions of external types without the compiler needing to recognize it. All the parser needs to recognize here is the *form* not the *function*. Nicolas wrote: > You must understand that returning nil is a simple way to indicate a > failure (a kind of C-style programming). Absolutely not. It is a query about "is there a type of that name"? Returning nil does not indicate failure - it indicates that no type by that name exist. Whether that denotes "failure" or a perfectly legal response is in the eye of the beholder (the sender of the message). As an example for this, look at the senders of #atomicTypeNamed: and notice how the response is used in a variety of ways none of which denotes "failure" in any way or shape. Cheers, - Andreas |
2006/7/19, Andreas Raab <[hidden email]>:
> Mathieu SUEN wrote: > > I ask those question because I am adding this to the new compiler. > > And why didn't you say so before? See ESR's essay where he talks about > "describe the goal not the steps". Your questions make a lot more sense > when you add just that single sentence for explaining why you're looking > at this code at all. ok I apologize it is true > > So I have to follow the same structur to get the ExternalType. But it > > seem to be not really pretty with nil value. > > It is a perfectly reasonable thing to do. The compiler is querying for > the existence of a type by that name. If there is none, the answer is > undefined, an UndefinedObject, e.g., nil. What is not pretty about it? Ok is because it is better to tell not to ask. :) A think that it is cool to see somthing like this: aExtType := descriptorClass externalType: aToken value ifAbsent: [ self interactive ifTrue:[^nil]. "otherwise go over it silently" aExtType := descriptorClass forceTypeNamed: aToken value ] And #externalType:ifAbsent:keyword do all the stuff of searching throw all you want (don't want to know). What do you think? Math |
In reply to this post by Mathieu SUEN
I agree, C-Style was not pejorative here. It is just a style consisting in checking returned value of functions (messages). Very simple in this case, and i'am OK with that. You answer the question which type has this name (nil means none), and testing isNil, you answer the question does such a type exist. This is something equivalent to Dictionary access like: ExternalType at: name ifAbsent: [nil]. And yes, nil is much cleaner than C implicit encoding (0, -1, 1 all can mean true, false, nil, failure, depending on the function). Nicolas Andreas Raab: > > Nicolas wrote: > > You must understand that returning nil is a simple way to indicate a > > failure (a kind of C-style programming). > > Absolutely not. It is a query about "is there a type of that name"? > Returning nil does not indicate failure - it indicates that no type by > that name exist. Whether that denotes "failure" or a perfectly legal > response is in the eye of the beholder (the sender of the message). As > an example for this, look at the senders of #atomicTypeNamed: and notice > how the response is used in a variety of ways none of which denotes > "failure" in any way or shape. > > Cheers, > - Andreas > > ________________________________________________________________________ iFRANCE, exprimez-vous ! http://web.ifrance.com |
In reply to this post by Mathieu SUEN
Mathieu SUEN wrote:
> A think that it is cool to see somthing like this: > > aExtType := descriptorClass externalType: aToken value ifAbsent: [ > self interactive ifTrue:[^nil]. > "otherwise go over it silently" > aExtType := descriptorClass forceTypeNamed: aToken value > ] So what is cool about it? Generally, I find the above pattern *very* hard to read and understand. There is a non-local return in the block, xType is assigned to inconsistently (both inside the block and as the result of evaluating the block), control-flow is mixed with data-flow, all of which make the code harder to read and interpret. And when you start extending the #ifAbsent: block and the first line moves outside your visual field, it is *very* easy to forget that the result of that block is potentially assigned to the variable. To illustrate, here is a little quiz for you: What are the possible results for xType after evaluating the following expression? [*] xType := descriptorClass atomicTypeNamed: here ifAbsent:[ (Symbol hasInterned: here ifTrue:[ xType := #foo. ]) ifFalse:[ xType := #bar. ]. ]. I think the result is very confusing and non-obvious so I'd rather see: xType := descriptorClass atomicTypeNamed: here ifAbsent:[nil]. xType ifNil:[ (Symbol hasInterned: here ifTrue:[ xType := #foo. ]) ifFalse:[ xType := #bar. ]. ]. This may be "uncool" but it sure as hell is also less surprising and more predictable. Generally, my rule of thumb is: If you have a single expression, like in count := dict at: key ifAbsent:[self defaultCount]. then it's fine to use it in that way. If you have a complex sequence of actions I prefer a style where I return a token and then take action depending on that token, say count := dict at: key ifAbsent:[token]. count == token ifTrue:[ "... go compute count ..." ]. This avoids the horrible mix of data and control flow by implicitly and inconsistently assigning to a variable multiple levels up (which is the root cause of the problem). Cheers, - Andreas [*] The answer is nil and #bar. The code never results in #foo because if that branch is taken the #ifAbsent: block actually evaluates to nil and *that* value is being assigned to xType. |
On Wed, 19 Jul 2006 21:05:22 +0200, Andreas Raab wrote:
... > This may be "uncool" but it sure as hell is also less surprising and > more predictable. No not uncool, only "maintainable" :) /Klaus |
Free forum by Nabble | Edit this page |