tag:blogger.com,1999:blog-6800934446457898793.post6237409105482969135..comments2009-03-17T13:43:22.486-04:00Comments on Moserware: Building an Object-Oriented Parasitic Metalanguage...Jeff Moserhttp://www.blogger.com/profile/16074905903060665396noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-6800934446457898793.post-1983323640707065672009-03-17T13:43:00.000-04:002009-03-17T13:43:00.000-04:00Thanks. I understand perfectly now. I thought th...Thanks. I understand perfectly now. I thought this was a parser being written in C#.GreGorhttp://www.blogger.com/profile/07815471805312437872noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-25989479857216701982009-03-17T13:28:00.000-04:002009-03-17T13:28:00.000-04:00GreGor: After this post was written, I changed "<:...GreGor: After this post was written, I changed "<:" to just be ":" to make it more like C#. OMeta#'s parser is written in OMeta itself. The rule that handles parsing this top level is <A HREF="http://ometasharp.codeplex.com/SourceControl/changeset/view/17706#360103" REL="nofollow">in OMetaParser.ometacs</A>. Specifically, look at the "Grammar" rule there.<BR/><BR/>Note the:<BR/><BR/>( ":" Name | Empty -> { "OMeta" } ):sn BaseTypeDef:btd<BR/><BR/>This means that it's expecting a ":" followed by whatever matches the "Name" rule. If it doesn't find this, it matches the "Empty" rule and that will return "OMeta" meaning that implied base grammar is "OMeta" unless you override it.Jeff Moserhttp://www.blogger.com/profile/16074905903060665396noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-58996316250401972042009-03-17T12:23:00.000-04:002009-03-17T12:23:00.000-04:00I'm still a bit confused about the <: operator. I...I'm still a bit confused about the <: operator. It is an operator I'm not aware of.<BR/><BR/>Where is a <: operator defined?<BR/><BR/>I've used the google - can't find anything.GreGorhttp://www.blogger.com/profile/07815471805312437872noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-2201598064315271612009-03-17T11:42:00.000-04:002009-03-17T11:42:00.000-04:00GreGor: The "<:" operator there means that the "Ca...GreGor: The "<:" operator there means that the "Calculator" grammar "inherits" from the "Parser" grammar. Essentially, this means that the "Calculator" grammar has access to all of "Parser"'s rules and can extend them or call back to the base grammar using the "Super" call.Jeff Moserhttp://www.blogger.com/profile/16074905903060665396noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-24258883662664959652009-03-17T11:11:00.000-04:002009-03-17T11:11:00.000-04:00what is the operator <: you're using for the calc ...what is the operator <: you're using for the calc + parser connection in the class declaration? Is it some sort of one way inheritance?GreGorhttp://www.blogger.com/profile/07815471805312437872noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-10155893847778831162008-08-06T23:19:00.000-04:002008-08-06T23:19:00.000-04:00Yes, thank you. I will be keeping track of your p...Yes, thank you. I will be keeping track of your progress. Godd luck.Kyle Lahnakoskihttp://www.blogger.com/profile/12480148399162216639noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-21488073221141707332008-08-05T22:58:00.000-04:002008-08-05T22:58:00.000-04:00kyle lahnakoski:After a first pass, it seems like ...kyle lahnakoski:<BR/><BR/>After a first pass, it seems like you could write YAY in OMeta. You could take advantage of OMeta's BNF-like syntax (e.g. 'WordChar = "_" | Digit | Letter')<BR/><BR/>OMeta# grammars are sort of like your "Parsers" concept but with a focus on OO and streams of anything.<BR/><BR/>An interesting thing about OMeta is that you can hand off your input stream to a foreign grammar. It's a way of getting object-oriented features without having to derive or do multiple inheritance. <BR/><BR/>As to your second question, in my current OMeta# code generator, all the variables are method-local. My parser keeps track of all of my variables used within the production/rule. If you look at the generated code, you'll notice that all of the local variables are emitted at the start of the method. This happens because I have a HashSet of all the variables while parsing the rule body.<BR/><BR/>In theory, I could check the host expression for variables to make sure that they were declared. <BR/><BR/>To really do it well for OMeta#, I'd need a much better host language understanding than I currently have so that I could do a richer semantic analysis. For example, the improved host language parser would be able to parse to trees like "[Method, op_add, [RegularString, "["], [VariableAccess, foo]]". With that richness of a tree like that, I could make sure that all the variable accesses had a corresponding variable definition using OMeta#'s host language predicates.<BR/><BR/>For right now, I'm going to keep it simple and punt the hard work to the host language compiler. Perhaps I'll emit in a comment the original OMeta# input so that when they see the compiler error in the host language they'll have better context.<BR/><BR/>Did that help answer your questions? Feel free to follow up.Jeff Moserhttp://www.blogger.com/profile/16074905903060665396noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-87475655900207478512008-08-05T15:59:00.000-04:002008-08-05T15:59:00.000-04:00Oh! I have not had the time to understand how OMe...Oh! I have not had the time to understand how OMeta (or others) could compile something like:<BR/><BR/><BR/>public class Example{<BR/><BR/> public String toString(){<BR/> return "("+x+", "+y+")";<BR/> }//method<BR/><BR/> <BR/> int x;<BR/> int y; <BR/> <BR/>}//class<BR/><BR/><BR/>...into a working piece of code YET give reasonable compiler errors on <BR/><BR/><BR/>public class Example{<BR/><BR/> public String toString(){<BR/> return "("+foo+", "+bar+")";<BR/> }//method<BR/><BR/> <BR/> int x;<BR/> int y; <BR/>}//class<BR/><BR/><BR/>This has more to do with the semantic analysis of handing a graph of objects with a given namespace, rather than simple parse trees.<BR/><BR/>Have you seen elegant OO-like solutions to this problem? Or am I still stuck in the world of low-level semantic analysis?Kyle Lahnakoskihttp://www.blogger.com/profile/12480148399162216639noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-20865082128554499692008-08-05T15:17:00.000-04:002008-08-05T15:17:00.000-04:00Jeff:Please forgive the deplorable state of my web...Jeff:<BR/><BR/>Please forgive the deplorable state of my web pages. I have not had the desire to clean up the look (or the ideas) in many years.<BR/><BR/>I have a write-up of what I was building:<BR/><BR/>http://www.arcavia.com/Software/YAY/index.html<BR/><BR/>If you really want code: The YAY runs in the DBOS, which can be found at:<BR/><BR/>http://www.arcavia.com/Software/DBOS/index.htmlKyle Lahnakoskihttp://www.blogger.com/profile/12480148399162216639noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-67401885859842880192008-08-02T10:32:00.000-04:002008-08-02T10:32:00.000-04:00domenic:Maybe the right approach is to at least of...domenic:<BR/><BR/>Maybe the right approach is to at least offer a version that will modify the semantic action { x + y } to use reflection to look for the add operator that is the most in line with what you want to do. You'd pay the cost of reflection, but you wouldn't have to annotate the type.<BR/><BR/>Another idea I had is that if you would annotate your grammar for what the input and default output types are, you wouldn't have to specify them elsewhere unless you wanted to "override" the defaults.<BR/><BR/>For example, "ometa Calculator<char, int> <: Parser { ... Number = Number:n Digit:d -> { n * 10 + d } ... }"<BR/><BR/>In this case, I'd rewrite the semantic action to cast things appropriately as I do now (e.g. .As<int>()). Then, I push the static analysis work to the C# compiler. It's sort of an extension of your first idea, but makes the common case cleaner by providing a default.<BR/><BR/>Ideally though, the Duck Typing will probably win out long term since it's less work (make the program work harder instead of the programmer). However, it'd be nice to have an explicitly typed one as well for performance reasons.<BR/><BR/>If anyone knows obvious DLR or other tricks that I'm missing, please speak up :)Jeff Moserhttp://www.blogger.com/profile/16074905903060665396noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-13679354540874889752008-08-01T14:09:00.000-04:002008-08-01T14:09:00.000-04:00Hmm, I see your point regarding where the grammar ...Hmm, I see your point regarding where the grammar is being changed. I dunno, seems worthwhile to me though; you're kind of extending OMeta to be more type-safe, which seems quite worthy of something called Omega# (emphasis on the sharp).<BR/><BR/>Regarding duck typing, I have absolutely no idea what I'm talking about, and feel especially bad saying anything given that people have presumably written papers about this. But with that said, my thought would be that maybe you don't need to actually identify x and y as ints, but rather as any type which has either an Add method or an overloaded + operator defined? So you'd just write<BR/><BR/>AddExpr = AddExpr:x '+' MulExpr:y -> { x + y }<BR/><BR/>And this would be shorthand for (making up syntax here)<BR/><BR/>AddExpr = AddExpr:x<T> '+' MulExpr:y<U> -> { x + y } where T : static Add(T, U)<BR/><BR/>I have no idea how the implementation details on this would work, but presumably all this can be done with compile-time checking: first figure out what operations are needed, then make sure that the appropriate types have them, given specific instances of T and U. This is kinda shaky though, since I'm not entirely clear on what's happening at compile time versus runtime. (Or rather, I've forgotten the details since I read this blog post the other day :P).Domenichttp://www.domenicdenicola.com/noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-48010857381148964552008-07-31T19:07:00.000-04:002008-07-31T19:07:00.000-04:00js:As I mentioned in the previous two posts, F# is...js:<BR/><BR/>As I mentioned in the previous two posts, F# is definitely a great language for the reason you mentioned (descendent of ML). However, I felt that it would unnecessarily burden people to get started with OMeta. If we use C#, then people could (in theory) add generated C# to their projects as if they wrote it by hand. It fits in with a gradual adoption of OMeta.<BR/><BR/>As for the runtime in C#, I'm trying to keep things as friction free as possible. If I would have required F#, that would have been an extra thing people would need to get started.<BR/><BR/>Besides, perhaps doing this first in a hard language like C# might pay off later with a better understanding of the platform :).<BR/><BR/>But regardless, yes -- F# is a fantastic language. I'm hoping to steal some good ideas from ML and friends.<BR/><BR/>--<BR/><BR/>domenic:<BR/><BR/>1. Very interesting thought! It would shave off 5 characters per variable reference and be parasitic with C#. Perhaps I could make that the standard way of specifying a type to give hints to weak type inference algorithm. <BR/><BR/>My only concern is that it would be a change to the OMeta parser grammar itself rather than to the Semantic action/expression. I don't suppose you have additional thoughts on how to get duck typing to work in this environment so that the <int> annotations wouldn't be needed?<BR/><BR/>2. I haven't seen this in the wild. But that looks like a good potential for a VS addin. My hope is that someone can show me the ropes of writing VS debugger support for OMeta itself. That way, instead of stepping through generated code, you're only dealing with the OMeta grammar source file itself (it'd highlight in yellow each rule application as it happened if you pressed F11).Jeff Moserhttp://www.blogger.com/profile/16074905903060665396noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-76738497809343558002008-07-31T18:34:00.000-04:002008-07-31T18:34:00.000-04:00Very neat :).Two things:1) I would imagine the syn...Very neat :).<BR/><BR/>Two things:<BR/><BR/>1) I would imagine the syntax could be much improved by replacing things like<BR/><BR/>AddExpr = AddExpr:x '+' MulExpr:y -> { x.As<int>() + y.As<int>() }<BR/><BR/>with, say,<BR/><BR/>AddExpr = AddExpr:x<int> '+' MulExpr:y<int> -> { x + y }<BR/><BR/>Especially when you end up calling .As<int> on the same object multiple times...<BR/><BR/><BR/>2) Debugging. One solution I kind of hope for is a "automatic step through"... it would be equivalent to pressing F11 every 1 second (or whatever), but you can just press (say) spacebar and it'll pause. I'm surprised I haven't seen this already... do you know of any such solution, maybe as a VS addin?Domenichttp://www.domenicdenicola.com/noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-33384264088025574042008-07-31T13:55:00.000-04:002008-07-31T13:55:00.000-04:00May I suggest that you take a look at F# as your i...May I suggest that you take a look at F# as your implementing language? ML-family languages in their own right lend themselves to language parser and compiler tasks. Hosting OMeta in it seems like the shortest route to providing OMeta .Net support.JSnoreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-25099391408646596332008-07-31T11:56:00.000-04:002008-07-31T11:56:00.000-04:00Kyle Lahnakoski:One small approach if you're using...Kyle Lahnakoski:<BR/><BR/>One small approach if you're using .NET, is to annotate a method with the "[DebuggerStepThrough]" attribute and it will give a hint to the debugger to step through it.<BR/><BR/>This helps a little in my "MetaRules" property in OMetaBase.cs (since it can be called literally thousands of times), but it is still far from ideal.<BR/><BR/>Do you have a URL for your project?Jeff Moserhttp://www.blogger.com/profile/16074905903060665396noreply@blogger.comtag:blogger.com,1999:blog-6800934446457898793.post-7245190505390550822008-07-31T09:08:00.000-04:002008-07-31T09:08:00.000-04:00"…debugging is annoyingly difficult… …stepping in..."…debugging is annoyingly difficult… …stepping into so many methods that fail often takes a long time…”<BR/><BR/><BR/>I would like to hear more of your ideas on how to solve this. My own (inferior) grammar language project stalled when these debugging and optimization problems became unbearable. Now I am working on compiler optimizations (assuming you consider a day-a-month still working).<BR/><BR/>ThanksKyle Lahnakoskinoreply@blogger.com