I have the following code definition:
type Tree* = ref ...
type Parser* = ref object
hooks: Table[string, proc(it: var Tree)]
template hook*(this: var Parser, rule: string, body: untyped) =
this.hooks[rule] = proc(it: var Tree) =
body
But I get an error "Error: undeclared identifier: 'it'" when trying to use it like:
let gp: Parser = ...
gp.hook("Value"):
echo $it
I expect this to be translated to:
gp.hooks["Value"] = proc(it: var Tree) =
echo $it
And this works fine.
Variables, types, formal parameters, and others in templates are gensym'd by default. gensym means to generate a guaranteed unique symbol to avoid name clashes outside of the template.
You can see how it is gensym'd with the following example:
template mkproc() =
proc foo(it: var Tree) =
echo it
mkproc()
foo()
Which will give you this compilation error:
Error: type mismatch got <> but expected one of:
proc foo(it`gensym123456: var Tree)
Where it is indeed gensym'd.
To fix hook, like your solution, is to tag a variable with {.inject.} since the parameter can't be tagged.
template hook*(this: var Parser, rule: string, body: untyped) =
this.hooks[rule] = proc(it: var Tree) =
var it {.inject.} = it
body
Lastly, templates used like hook can benefit from {.dirty.}. This will tag all symbols as {.inject.} including the proc parameters.
template hook*(this: var Parser, rule: string, body: untyped) {.dirty.} =
this.hooks[rule] = proc(it: var Tree) =
body
parser.hook "rule":
echo it
OK, I found the solution:
template hook*(this: var Parser, rule: string, body: untyped) =
this.hooks[rule] = proc(tree: var Tree) =
var it {.inject.} = tree
body
But this is unexpected since 'it' is already in a scope!
Related
I am trying to incorporate Stored Procedure written in Javascript into Terraform for Snowflake, when I tried to apply script as it was developed I was getting bellow error:
A reference to a resource type must be followed by at least one attribute access, specifying the resource name
Based on the line numbers which raised the error message it does not like the dollar sign, so it seems like it needs to get escaped, example of such un-altered lines are below:
if (rowCount == 0) return `Error: Script with SCRIPT_TYPE = ${SCRIPT_TYPE} and ACCES_TYPE = ${ACCES_TYPE} does not exist.`;
var sql = `select PARAMETER_NAMES, TEMPLATE from administration.utils.SCRIPT_TEMPLATE where SCRIPT_TYPE = ''${SCRIPT_TYPE}'' AND ACCES_TYPE = ''${ACCES_TYPE}''`
What I am after is to know how to escape it and have this logic using the replace function incorporated in procedure resource creation resource "snowflake_procedure" as to be seen below, so that any future changes to the logic or introduction of new procedures does not have to be manually altered, my attempt was to use '\$' for escaping in the function, however not successful:
resource "snowflake_procedure" "GENERATE_SCRIPT_FROM_TEMPLATE" {
name = "GENERATE_SCRIPT_FROM_TEMPLATE"
database = "ADMINISTRATION"
schema = "UTILS"
language = "JAVASCRIPT"
arguments {
SCRIPT_TYPE = "arg1"
type = "VARCHAR(250)"
}
arguments {
ACCES_TYPE = "arg2"
type = "VARCHAR(250)"
}
arguments {
PARAMETER_VALUES = "arg3"
type = "VARCHAR(5000)"
}
return_type = "VARCHAR"
execute_as = "OWNER"
statement = replace(
<<EOT
try
{
var parameterValues = JSON.parse(PARAMETER_VALUES);
}
catch (err) {
return `Failed to parse PARAMETER_VALUES: ${PARAMETER_VALUES}. Correct format is: {"DATABASE": "ADMINISTRATOR", "SCHEMA": "UTILS"}.`;
}
var sql = `select PARAMETER_NAMES, TEMPLATE from administration.utils.SCRIPT_TEMPLATE where SCRIPT_TYPE = ''${SCRIPT_TYPE}'' AND ACCES_TYPE = ''${ACCES_TYPE}''`
var stmt = snowflake.createStatement({ sqlText: sql });
var result = stmt.execute();
var rowCount = result.getRowCount();
if (rowCount == 0) return `Error: Script with SCRIPT_TYPE = ${SCRIPT_TYPE} and ACCES_TYPE = ${ACCES_TYPE} does not exist.`;
result.next();
var parameterNames = result.getColumnValue(1);
var scriptTemplate = result.getColumnValue(2);
var parameterNamesArray = parameterNames.split('','');
parameterNamesArray.forEach(parameterName => {
if (!parameterValues[parameterName]) return `Failed: Cannot find parameter ${parameterName} in PARAMETER_VALUES: ${PARAMETER_VALUES}.`
});
var oldStrimg = '''';
var newString = '''';
var script = scriptTemplate;
parameterNamesArray.forEach(parameterName => {
oldStrimg = `<${parameterName}>`;
newString = parameterValues[parameterName];
script = script.replace(oldStrimg,newString);
});
return script;
EOT
, "$", "'\$'")
}
What I did to escape $$ was to use another sign
For example (sql scripting)
let q := $$ ... ## something ## $$
q := replace(:q, '##', '$$')
const test ="[{contactId=2525, additionDetail=samle}]";
I need to convert this string to a JSON object. It will dynamically load like this string. I need to particular string to convert to a JSON object.
JSON.parse(test) command not working for this. I attached the error here.
For that specific string, you'd have to parse it yourself.
const test = '[{contactId=2525, additionDetail=samle}]';
const obj = {};
test.split(/[{}]/)[1].split(/, /).forEach((elm) => {
const entry = elm.split('=');
obj[entry[0]] = entry[1];
});
What I am doing is splitting the string on the braces and selecting the second element (utilising regex) then splitting that on comma and space (again regex) then loop over the result and assign to an object.
You can then JSON.stringify(obj) for the result.
:edit:
For the second string you've asked for there is another, potentially more refined, answer. You'll need to first replace the = with : (I've again used a regex), then you use a regex to match the words and sentence and use a function to add the quotes.
const test = '[{contactId=2525, additionDetail=samle}]';
const test2 = "[{contactId=2525, additionDetail=rrr additional Detail, medicationType={medicationTypeId=3333, medicationType=Tablet}, endDate=2022-12-30}]";
const replaced = test.replace(/=/g,':')
const replaced2 = test2.replace(/=/g, ':');
const replacer = function(match){
return '"' + match + '"';
}
const replacedQuote = replaced.replace(/(?!\s)[-?\w ?]+/g,replacer);
const replaced2Quote = replaced2.replace(/(?!\s)[-?\w ?]+/g,replacer);
const obj = JSON.parse(replacedQuote);
const obj2 = JSON.parse(replaced2Quote);
You should note that Json means javascript object notation, so you need to create a JavaScript object to get started:
const test ="[{contactId=2525, additionDetail=samle}]";
let obj = Object.create(null)
You can now define your variable as one of the object properties :
obj.test = test
Now we have a JavaScript object and we can convert it to json:
let convertedToJson = JSON.stringify(test);
[{contactId=2525, additionDetail=samle}]
this is not a valid JSON-string, and it cannot be parsed by JSON.parse()
the correct JSON-string would be:
const test ='[{"contactId":2525, "additionDetail":"samle"}]';
I'm experimenting around the idea of a simple logger that would look like this:
log(constant: String, _ variable: [String: AnyObject]? = nil)
Which would be used like this:
log("Something happened", ["error": error])
However I want to prevent misuse of the constant/variable pattern like the following:
log("Something happened: \(error)") // `error` should be passed in the `variable` argument
Is there a way to make sure that constant wasn't constructed with a string interpolation?
You could use StaticString instead of String:
func log(constant: StaticString, _ variable: [String: AnyObject]? = nil) {
// You can retrieve `String` from `StaticString`
let msg = constant.stringValue
}
let foo = 1
log("test \(foo)") // -> error: cannot invoke 'log' with an argument list of type '(String)'
Hi I don't know what exactly do this kind of sentences:
var v1 = new class(params) , object = {}
The real example was: (From https://github.com/visionmedia/parted Usage paragraph)
var parser = new multipart(type, options) , parts = {};
I understand that parser will be a new multipart object, but parts?! what exactly do? Create empty object? where I have to push some data?
Thank's in advice!
var declarations can take multiple variables. Example:
var a = 1, b = 2;
That declares two variables, a and b, and assigns them the values 1 and 2, respectively.
In other words, in your example, parts is a new variable that is assigned an "empty" object.
{} in javascript creates a new empty object using JavaScript's literal object notation.
Other examples of creating objects using the literal object notation:
obj1 = { foo: 2 } // Now obj1.foo is 2
obj2 = { foo: 3, bar: "hello" } // Now obj2.foo is 3 and obj2.bar is "hello"
I'm trying to write an expression that will call ToString on a property and assign it's value to a local variable. However, calling ToString on a object instance w/ an overload of ToString, causes an exception of "Ambigous Match Found" to be thrown. Here's an example:
var result = Expression.Variable(typeof(string), "result");
var matchTypeParameter = Expression.Parameter(typeof(MatchType), "matchType");
var targetProperty = Expression.Property(leadParameter, target);
var exp = Expression.Block(
//Add the local current value variable
new[] { result },
//Get the target value
Expression.Assign(result, Expression.Call(targetProperty, typeof(string).GetMethod("ToString"), null))
);
How can I call ToString if the instance has overloads for it? Thanks!
Replace:
typeof(string).GetMethod("ToString")
With:
typeof(string).GetMethod("ToString", Type.EmptyTypes)
In other words, get the method named "ToString" that takes zero arguments (empty type array).