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 &quot;&lt;:&quot; to just be &quot;:&quot; to make it more like C#. OMeta#&#39;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 &quot;Grammar&quot; rule there.<BR/><BR/>Note the:<BR/><BR/>( &quot;:&quot; Name | Empty -&gt; { &quot;OMeta&quot; } ):sn BaseTypeDef:btd<BR/><BR/>This means that it&#39;s expecting a &quot;:&quot; followed by whatever matches the &quot;Name&quot; rule. If it doesn&#39;t find this, it matches the &quot;Empty&quot; rule and that will return &quot;OMeta&quot; meaning that implied base grammar is &quot;OMeta&quot; 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&#39;m still a bit confused about the &lt;: operator. It is an operator I&#39;m not aware of.<BR/><BR/>Where is a &lt;: operator defined?<BR/><BR/>I&#39;ve used the google - can&#39;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 &quot;&lt;:&quot; operator there means that the &quot;Calculator&quot; grammar &quot;inherits&quot; from the &quot;Parser&quot; grammar. Essentially, this means that the &quot;Calculator&quot; grammar has access to all of &quot;Parser&quot;&#39;s rules and can extend them or call back to the base grammar using the &quot;Super&quot; 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 &lt;: you&#39;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&#39;d pay the cost of reflection, but you wouldn&#39;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&#39;t have to specify them elsewhere unless you wanted to &quot;override&quot; the defaults.<BR/><BR/>For example, &quot;ometa Calculator&lt;char, int&gt; &lt;: Parser { ... Number = Number:n Digit:d -&gt; { n * 10 + d } ... }&quot;<BR/><BR/>In this case, I&#39;d rewrite the semantic action to cast things appropriately as I do now (e.g. .As&lt;int&gt;()). Then, I push the static analysis work to the C# compiler. It&#39;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&#39;s less work (make the program work harder instead of the programmer). However, it&#39;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&#39;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&#39;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&#39;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&#39;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&#39;d just write<BR/><BR/>AddExpr = AddExpr:x &#39;+&#39; MulExpr:y -&gt; { x + y }<BR/><BR/>And this would be shorthand for (making up syntax here)<BR/><BR/>AddExpr = AddExpr:x&lt;T&gt; &#39;+&#39; MulExpr:y&lt;U&gt; -&gt; { 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&#39;m not entirely clear on what&#39;s happening at compile time versus runtime. (Or rather, I&#39;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&#39;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&#39;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&#39;t suppose you have additional thoughts on how to get duck typing to work in this environment so that the &lt;int&gt; annotations wouldn&#39;t be needed?<BR/><BR/>2. I haven&#39;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&#39;re only dealing with the OMeta grammar source file itself (it&#39;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 &#39;+&#39; MulExpr:y -&gt; { x.As&lt;int&gt;() + y.As&lt;int&gt;() }<BR/><BR/>with, say,<BR/><BR/>AddExpr = AddExpr:x&lt;int&gt; &#39;+&#39; MulExpr:y&lt;int&gt; -&gt; { x + y }<BR/><BR/>Especially when you end up calling .As&lt;int&gt; on the same object multiple times...<BR/><BR/><BR/>2) Debugging. One solution I kind of hope for is a &quot;automatic step through&quot;... it would be equivalent to pressing F11 every 1 second (or whatever), but you can just press (say) spacebar and it&#39;ll pause. I&#39;m surprised I haven&#39;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