How can I contruct a `X?` concrete syntax value? - rascal

I have this concrete syntax:
syntax SomeMore = [...] SyncBlock? sync;
syntax SyncBlock = "sync" "{" SyncStatement* stats "}";
syntax SyncStatement = [...];
[SyncBlock]"sync { <syncStrings> }" seems to work, but when I try to use it as a SyncBlock? and assign it:
SyncBlock? sync = [SyncBlock?]"sync { <syncStrings> }"
it does not work: inline parsing not supported on SyncBlock?, what is the easiest way to build up a value of this X?-type?
Can I convert a SyncBlock to a SyncBlock? somehow?
Something like this also doesn’t work:
syncBlock = (SyncBlock?)`sync { <SyncStatement* syncs>}`;
P.S. SyncBlock? syncBlock = … results in Ambiguous code (internal error), SyncBlock? syncBlock = …. Probably due to a ternary operator ambiguity?

I found a workaround, not ideal, but it works.
It seems that the ? in the types introduces some difficulties, but can be circumvented using an "alias" for this type:
I changed the grammar to:
syntax SomeMore = [...] MaybeSyncBlock sync;
syntax MaybeSyncBlock = SyncBlock?;
syntax SyncBlock = "sync" "{" SyncStatement* stats "}";
syntax SyncStatement = [...];
Now this works:
MaybeSyncBlock syncBlock = [MaybeSyncBlock]"sync { <syncStrings> }";

Related

Expected identifier when parsing expression, got 'nil'

local httpService = game :GetService("HttpService")
local laber = script.Parent.SurfaceGui.TextLabel
local URL = "https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=false"
local Data = httpService:GetAsync(URL)
local randomJokes = httpService:JSONDecode(Data)
nil.Text = randomJokes.value
Literals can't be used as "prefix expressions" to prefix .name, [exp] for assignments.
The workaround is to wrap literals in parentheses (for example: ("str"):rep(42)).
In your case, you can syntactically fix your code by wrapping nil in parentheses:
(nil).Text = randomJokes.value
which most likely is nonsense semantically, unless someone did
debug.setmetatable(nil, {__newindex = function(_, key, value) ... end})
What did you intend to achieve?

Implement heredocs with trim indent using PEG.js

I working on a language similar to ruby called gaiman and I'm using PEG.js to generate the parser.
Do you know if there is a way to implement heredocs with proper indentation?
xxx = <<<END
hello
world
END
the output should be:
"hello
world"
I need this because this code doesn't look very nice:
def foo(arg) {
if arg == "here" then
return <<<END
xxx
xxx
END
end
end
this is a function where the user wants to return:
"xxx
xxx"
I would prefer the code to look like this:
def foo(arg) {
if arg == "here" then
return <<<END
xxx
xxx
END
end
end
If I trim all the lines user will not be able to use a string with leading spaces when he wants. Does anyone know if PEG.js allows this?
I don't have any code yet for heredocs, just want to be sure if something that I want is possible.
EDIT:
So I've tried to implement heredocs and the problem is that PEG doesn't allow back-references.
heredoc = "<<<" marker:[\w]+ "\n" text:[\s\S]+ marker {
return text.join('');
}
It says that the marker is not defined. As for trimming I think I can use location() function
I don't think that's a reasonable expectation for a parser generator; few if any would be equal to the challenge.
For a start, recognising the here-string syntax is inherently context-sensitive, since the end-delimiter must be a precise copy of the delimiter provided after the <<< token. So you would need a custom lexical analyser, and that means that you need a parser generator which allows you to use a custom lexical analyser. (So a parser generator which assumes you want a scannerless parser might not be the optimal choice.)
Recognising the end of the here-string token shouldn't be too difficult, although you can't do it with a single regular expression. My approach would be to use a custom scanning function which breaks the here-string into a series of lines, concatenating them as it goes until it reaches a line containing only the end-delimiter.
Once you've recognised the text of the literal, all you need to normalise the spaces in the way you want is the column number at which the <<< starts. With that, you can trim each line in the string literal. So you only need a lexical scanner which accurately reports token position. Trimming wouldn't normally be done inside the generated lexical scanner; rather, it would be the associated semantic action. (Equally, it could be a semantic action in the grammar. But it's always going to be code that you write.)
When you trim the literal, you'll need to deal with the cases in which it is impossible, because the user has not respected the indentation requirement. And you'll need to do something with tab characters; getting those right probably means that you'll want a lexical scanner which computes visible column positions rather than character offsets.
I don't know if peg.js corresponds with those requirements, since I don't use it. (I did look at the documentation, and failed to see any indication as to how you might incorporate a custom scanner function. But that doesn't mean there isn't a way to do it.) I hope that the discussion above at least lets you check the detailed documentation for the parser generator you want to use, and otherwise find a different parser generator which will work for you in this use case.
Here is the implementation of heredocs in Peggy successor to PEG.js that is not maintained anymore. This code was based on the GitHub issue.
heredoc = "<<<" begin:marker "\n" text:($any_char+ "\n")+ _ end:marker (
&{ return begin === end; }
/ '' { error(`Expected matched marker "${begin}", but marker "${end}" was found`); }
) {
const loc = location();
const min = loc.start.column - 1;
const re = new RegExp(`\\s{${min}}`);
return text.map(line => {
return line[0].replace(re, '');
}).join('\n');
}
any_char = (!"\n" .)
marker_char = (!" " !"\n" .)
marker "Marker" = $marker_char+
_ "whitespace"
= [ \t\n\r]* { return []; }
EDIT: above didn't work with another piece of code after heredoc, here is better grammar:
{ let heredoc_begin = null; }
heredoc = "<<<" beginMarker "\n" text:content endMarker {
const loc = location();
const min = loc.start.column - 1;
const re = new RegExp(`^\\s{${min}}`, 'mg');
return {
type: 'Literal',
value: text.replace(re, '')
};
}
__ = (!"\n" !" " .)
marker 'Marker' = $__+
beginMarker = m:marker { heredoc_begin = m; }
endMarker = "\n" " "* end:marker &{ return heredoc_begin === end; }
content = $(!endMarker .)*

Nix: nixlang syntax how to change an existing set ? Syntax error unexpected '=' , expecting $end

nix repl
nix-repl> test = {"a"=10;}
nix-repl> test.a
nix-repl> 10
nix-repl> test.a=20
error: syntax error, unexpected '=' , expecting $end, at (string):1:7
Expected result:
test = {"a"=20;}
I am currently learning nix and couldn't find the answer after a few minutes of google.
This seems rather simple and I'm sure someone instantly knows this.
Values in nix are immutable; you can't change the value of test.a, because that would require changing the set. You can only create a new set with a different a value.
nix-repl> test = {"a"=10;}
nix-repl> test // {"a"=20;}
{ a = 20; }
nix-repl> test
{ a = 10; }
nix-repl> test2 = test // {"a"=20;}
nix-repl> test2
{ a = 20; }
The // operator combines two sets, with values on the right-hand side overriding values on the left.
nix-repl> {"a"=10; "b"=20;} // {"a"="changed"; c="30";}
{ a = "changed"; b = 20; c = "30"; }

Parsing string with more then 15 characters with boost-spirit

I have a somewhat simple problem that i somehow cannot find any answers for. While working on parsing a larger grammar, i discovered that parsing any string larger then 15 characters would lead the parser to return as failed. The parser looks like this:
namespace parser {
template <typename Iterator>
struct p_grammar : qi::grammar<Iterator, standard::space_type> {
p_grammar() : p_grammar::base_type(spec) {
spec = "qwertyuiopasdfgh";
}
qi::rule<Iterator, standard::space_type> spec;
};
And will be run from within another function:
void MainWindow::parserTest() {
typedef parser::p_grammar<std::string::const_iterator> p_grammar;
p_grammar grammar;
using boost::spirit::standard::space;
std::string::const_iterator iter = editor->toPlainText().toStdString().begin();
std::string::const_iterator end = editor->toPlainText().toStdString().end();
if ( phrase_parse(iter,end,grammar,space) ) {
outputLog->append("Parsing succesfull");
} else {
outputLog->append("Parsing failed");
}
}
Removing the last character in "qwertyuiopasdfgh", so only 15 characters are present, makes it parse without failure.
Feel like I'm overlooking something obvious here.
You should be using valid iterators:
std::string value = editor->toPlainText().toStdString()
std::string::const_iterator iter = value.begin(), end = value.end();
You were using iterators into a temporary that wasn't stored.

syntax error, unexpected '}', expecting ':' Rails

I'd like to remove this part :
"company.html?#{token_url}&company=#{URI.encode(current_company.trylive_name)}" but an error appears syntax error, unexpected '}', expecting ':'
#iframe_statistics_url = "#{Gaston.amazon.cloudfront.host}/trylive_dashboard/iframe/#{current_user.has_role?(:administrator) ? "companies.html?#{admin_token_url}" : "company.html?#{token_url}&company=#{URI.encode(current_company.trylive_name)}"}"
You can't use double quotes(") inside double quotes. You need to escape those quotes:
"Hello, "are you there?" # doesn't make sense in Ruby
"Hello, \"are you there?" # escaped double quotes inside the string
#VtrKanna
#iframe_statistics_url = "#{Gaston.amazon.cloudfront.host}/trylive_dashboard/iframe/#{current_user.has_role?(:administrator) ? "companies.html?#{admin_token_url}" : "company.html?#{token_url}&company=#{URI.encode(current_company.trylive_name)}"}"
this is work fine
but my problem is just to keep this part
#iframe_statistics_url = "#{Gaston.amazon.cloudfront.host}/trylive_dashboard/iframe/#{current_user.has_role?(:administrator) ? "companies.html?#{admin_token_url}"}"
this is result an error
Try like this
val = current_user.has_role?(:administrator) ? "companies.html?#{admin_token_url}" : "company.html?#{token_url}&company=#{URI.encode(current_company.trylive_name)}"
#iframe_statistics_url = "#{Gaston.amazon.cloudfront.host}/trylive_dashboard/iframe/}#{val}"
Or
g = "https://www.google.co.in/"
q = %[helo #{"world #{g}"}]
=> "helo world https://www.google.co.in/"
Try it
#iframe_statistics_url = %[#{Gaston.amazon.cloudfront.host}/trylive_dashboard/iframe/companies.html?#{current_user.has_role?(:administrator) ? admin_token_url : "#{token_url}&company=#{URI.encode(current_company.trylive_name)}"}]

Resources