How to create nested macro in Boo - boo

I am creating nested macros in Boo, I wrote this program:
macro text:
macro subMacro:
text["Text"] = "Hello World"
return [|
block:
System.Console.WriteLine( "Hello World" );
|]
But I am getting the error "Unknown Identifer: 'text'" in the 3rd line of the code.

The error you are getting is likely to do with a missing import in the code where the macro is being called from.
If your macro is in a namespace named foo for example, you will need to add
import foo
At the top of the calling code.
A second issue you may run into once you fix this compiler issue is the error
"Unknown identifier 'block' (BCE0005)
To fix this, add a .Body after the quasi-quotation section like this:
import Boo.Lang.Compiler.Ast
macro text:
macro subMacro:
text["Text"] = "Hello world"
return [|
block:
System.Console.WriteLine("Hello World");
|].Body
EDIT - IMHO macros are a bit of a dark art. For more help, you should try the boo mailing list, or the excellent DSLs in BOO

Related

SuperCollider * marking the constructor method is not expected

I tried to create a Class and the constructor always gave me a Syntax Error about the *new method then I just copied the Example from the documentation:
MyClass {
// this is a normal constructor method
*new { | arga, argb, argc |
^super.new.init(arga, argb, argc)
}
init { | arga, argb, argc |
// do initiation here
}
}
and still got this:
ERROR: syntax error, unexpected '*', expecting '}'
in interpreted text
line 6 char 5:
*new { | arga, argb, argc |
^
^super.new.init(arga, argb, argc)
-----------------------------------
ERROR: Command line parse failed
-> nil
From my own class i get the same error concerning the constructor. Where am I wrong?
If you check out the Writing Classes helpfile, there's a bit at the top that's easy to miss about where to save your classes.
https://depts.washington.edu/dxscdoc/Help/Guides/WritingClasses.html
NOTE: Class definitions are statically compiled when you launch
SuperCollider or "recompile the library." This means that class
definitions must be saved into a file with the extension .sc, in a
disk location where SuperCollider looks for classes. Saving into the
main class library (SCClassLibrary) is generally not recommended. It's
preferable to use either the user or system extension directories.
Platform.userExtensionDir; // Extensions available only to your user account
Platform.systemExtensionDir; // Extensions available to all users on the machine
It is not possible to enter a class definition into an interpreter
window and execute it.
The the Save As Extension option under the file menu. Then recompile the interpretter and try using your class.

dynamic usage of attribute in recipe

I am trying to increment the value and use in another resource dynamically in recipe but still failing to do that.
Chef::Log.info("I am in #{cookbook_name}::#{recipe_name} and current disk count #{node[:oracle][:asm][:test]}")
bash "beforeTest" do
code lazy{ echo #{node[:oracle][:asm][:test]} }
end
ruby_block "test current disk count" do
block do
node.set[:oracle][:asm][:test] = "#{node[:oracle][:asm][:test]}".to_i+1
end
end
bash "test" do
code lazy{ echo #{node[:oracle][:asm][:test]} }
end
However I'm still getting the error bellow:
NoMethodError ------------- undefined method echo' for Chef::Resource::Bash
Cookbook Trace: ---------------
/var/chef/cache/cookbooks/Oracle11G/recipes/testSplit.rb:3:in block (2 levels) in from_file'
Resource Declaration: ---------------------
# In /var/chef/cache/cookbooks/Oracle11G/recipes/testSplit.rb
1: bash "beforeTest" do
2: code lazy{
3: echo "#{node[:oracle][:asm][:test]}"
4: }
5: end
Please can you help how lazy should be used in bash? If not lazy is there any other option?
bash "beforeTest" do
code lazy { "echo #{node[:oracle][:asm][:test]}" }
end
You should quote the command for the interpolation to work; if not, ruby would search for an echo command, which is unknown in ruby context (thus the error you get in log).
Warning: lazy has to be for the whole resource attribute; something like this WON'T work:
bash "beforeTest" do
code "echo node asm test is: #{lazy { node[:oracle][:asm][:test]} }"
end
The lazy evaluation takes a block of ruby code, as decribed here
You may have a better result with the log resource like this:
log "print before" do
message lazy { "node asm test is #{node[:oracle][:asm][:test]}" }
end
I've been drilling my head solving this problem until I came up with lambda expressions. But yet just using lambda didn't help me at all. So I thought of using both lambda and lazy evaluation. Though lambda is already lazy loading, when compiling chef recipe's, the resource where you call the lambda expression is still being evaluated. So to prevent it to being evaluated (somehow), I've put it inside a lazy evaluation string.
The lambda expression
app_version = lambda{`cat version`}
then the resource block
file 'tmp/validate.version' do
user 'user'
group 'user_group'
content lazy { app_version.call }
mode '0755'
end
Hope this can help others too :) or if you have some better solution please do let me know :)

ExecJS: keeping the context between two calls

I'm currently trying to use ExecJS to run Handlebars for one of the product I work on (note: I know the handlebars.rb gem which is really cool and I used it for some times but there is issues to get it installed on Windows, so I try another homemade solution).
One of the problem I'm having is that the Javascript context is not kept between each "call" to ExecJS.
Here the code where I instantiate the #js attribute:
class Context
attr_reader :js, :partials, :helpers
def initialize
src = File.open(::Handlebars::Source.bundled_path, 'r').read
#js = ExecJS.compile(src)
end
end
And here's a test showing the issue:
let(:ctx) { Hiptest::Handlebars::Context.new }
it "does not keep context properly (or I'm using the tool wrong" do
ctx.js.eval('my_variable = 42')
expect(ctx.js.eval('my_variable')).to eq(42)
end
And now when I run it:
rspec spec/handlebars_spec.rb:10 1 ↵
I, [2015-02-21T16:57:30.485774 #35939] INFO -- : Not reporting to Code Climate because ENV['CODECLIMATE_REPO_TOKEN'] is not set.
Run options: include {:locations=>{"./spec/handlebars_spec.rb"=>[10]}}
F
Failures:
1) Hiptest::Handlebars Context does not keep context properly (or I'm using the tool wrong
Failure/Error: expect(ctx.js.eval('my_variable')).to eq(42)
ExecJS::ProgramError:
ReferenceError: Can't find variable: my_variable
Note: I got the same issue with "exec" instead of "eval".
That is a silly example. What I really want to do it to run "Handlebars.registerPartial" and later on "Handlebars.compile". But when trying to use the partials in the template it fails because the one registered previously is lost.
Note that I've found a workaround but I find it pretty ugly :/
def register_partial(name, content)
#partials[name] = content
end
def call(*args)
#context.js.call([
"(function (partials, helpers, tmpl, args) {",
" Object.keys(partials).forEach(function (key) {",
" Handlebars.registerPartial(key, partials[key]);",
" })",
" return Handlebars.compile(tmpl).apply(null, args);",
"})"].join("\n"), #partials, #template, args)
end
Any idea on how to fix the issue ?
Only the context you create when you call ExecJS.compile is preserved between evals. Anything you want preserved needs to be part of the initial compile.

CLR IL-significance of square bracket on .locals init

I am trying to generate a dynamic assembly using Reflection & Emit in .NET. I am getting an error, "Common Language Runtime detected an invalid program." I created another program which has the functionality I want using hard-coded types. The functionality I am trying to write will ultimately use dynamic types, but I can use ILDasm to see the IL I need to generate. I am comparing the IL I am generating with the IL which the compiler generates. In the .locals init declaration of one method I see there is an extra item in the compiler-generated code,
compiler-generated:
.locals init ([0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
[1] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001)
mine:
.locals init (class [System.Core]System.Linq.Expressions.ParameterExpression V_0,
class [System.Core]System.Linq.Expressions.ParameterExpression[] V_1)
I don't understand the significance of the "[0]" and "[1]" in the compiler-generated code. Can anyone tell me what it means?
As a more general question, I can follow most ILDasm output without too much trouble. But every so often I run across a problematic expression. For instance, in this line from ILDasm
callvirt instance class [EntityFramework]System.Data.Entity.ModelConfiguration.EntityTypeConfiguration`1<!!0> [EntityFramework]System.Data.Entity.DbModelBuilder::Entity<class DynamicEdmxTrial.HardFooAsset>()
the "!!0" probably refers to the generic type of the Entity<>, but I don't know for sure, and I wonder if there is a key to ILDasm output that would explain its more obscure output to me.
The specification is freely available here. It takes a little getting used to, but most details are easily found once you figure out the structure.
!! is listed in II.7.1 Types:
Type ::= | Description | Clause
‘!’ Int32 | Generic parameter in a type definition, | §II.9.1
| accessed by index from 0 |
| ‘!!’ Int32 | Generic parameter in a method | §II.9.2
| definition, accessed by index from 0 |
...
In other words, inside a method that C# would call f<T, U>(), !!0 would be T, and !!1 would be U.
However, the [0] is a good question. The spec does not seem to address it. The .locals directive is described in II.15.4.1.3 The .locals directive, which lists the syntax as
MethodBodyItem ::= ...
| .locals [ init ] ‘(’ LocalsSignature ‘)’
LocalsSignature ::= Local [ ‘,’ Local ]*
Local ::= Type [ Id ]
There is nothing that seems to allow [0] there unless it is part of a Type, and Type does not allow anything starting with [ either. My guess is that this is an undocumented peculiarity specific to Microsoft's implementation, intended to help the human reader see that location 0 is local variable CS$0$0000, for when the generated instructions access local variables by index.
Experimenting with ILAsm shows that this is exactly what it means. Taking a simple C# program:
static class Program {
static void Main() {
int i = 0, j = 1;
}
}
and compiling and then disassembling it (csc test.cs && ildasm /text test.exe >test.il) shows:
....
.locals init (int32 V_0,
int32 V_1)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: ldc.i4.1
IL_0004: stloc.1
IL_0005: ret
....
Modifying the .locals to
.locals init ([0] int32 V_0, [0] int32 V_1)
gives a useful warning message:
test.il(41) : warning : Local var slot 0 is in use
And indeed, declaring variables of different types, then reordering them using [2], [1], [0], assembling and immediately disassembling the result, shows that the variables got reordered.

Run a gdb macro for all files in a directory

I want to create a macro for which a directory path will be given. The macro in-turn has to run another macro for all the files in the directory. Is that possible in gdb ?
I assume that the macro you want to run is a gdb macro. To solve this, I suggest you use the Python support in gdb to encompass this. Put the following in forallindir.py
import gdb
import os
class ForAllInDir (gdb.Command):
"Executes a gdb-macro for all files in a directory."
def __init__ (self):
super (ForAllInDir, self).__init__ ("forallindir",
gdb.COMMAND_SUPPORT,
gdb.COMPLETE_NONE, True)
def invoke(self, arg, from_tty):
arg_list = gdb.string_to_argv(arg)
path = arg_list[0]
macro = arg_list[1]
for filename in os.listdir(path):
gdb.execute(macro + ' ' + os.path.join(path, filename))
ForAllInDir()
Then in gdb to source forallindir.py and it should work. For example, define a test macro like
define testit
print "i got called with $arg0"
end
and forallindir /tmp/xx testit with two sample files in that directory will give us
$1 = "i got called with /tmp/xx/ape"
$2 = "i got called with /tmp/xx/bear"
Hope that helps.

Resources