How can I create a goto expression in xtext? - eclipse

I want to create a goto expression as follows
//label
<bb 2> :
//goto
goto <bb 2>;
The following grammar works fine for a simple ID. I have no idea how to reference the <ID INT>
in the goto expression.
Goto returns Goto:
{Goto}
'goto' goto+=[Label] ';'
;
LabelDef returns LabelDef:
{LabelDef}
label+= Label ':'
;
Label returns Label:
{Label}
name= ID
;
Do have any idea how to that?

the feature you are looking for is a DataType rule
Goto returns Goto:
{Goto}
'goto' goto+=[Label|IDandINT] ';'
;
LabelDef returns LabelDef:
{LabelDef}
label+= Label ':'
;
Label returns Label:
{Label}
name= IDandINT
;
IDandINT: ID INT;
you may also introduce / customize DefaultTerminalConverters/IValueConverter for the datatype rule to normalize whitespace

I think you want a terminal that is essentially "ID INT" and then use it to crossreference your Label.
I think this is going to be a lot of work just to be able to allow "spaces" in your labels. Why not simply rely on terminal "ID" and users may name them "bb2" if they wish?

Related

Postgres regexp_replace, using function on 3rd parameter

Using Postgres 9.4, is it possible to apply a function on the captured match?
Example: upper case only the string which are surrounded by double-quotes.
SELECT regexp_replace(
'123, "name", ignored~me, "Beer & Cheese", pi=3.14',
'"(.+?)"',
upper('"\1"'),
'g'
);
--Result : '123, "name", ignored~me, "Beer & Cheese", pi=3.14'
--Expected: '123, "NAME", ignored~me, "BEER & CHEESE", pi=3.14'
It looks like the function appearing in the 3rd parameter of regexp_replace is ignored. Is there anyway to use a function and passing the \n group capture as input argument?
I once had same question, and this
I did not get the answer, but general impression that you are not supposed to use SQL functions on arguments of regular expression functions...
In SQL, functions aren't first-class. They can't be passed. There is no part of the language that's interpreted either. It's declarative, compiled (with an optimizer), and evaluated strictly.
Keep in mind, under normal circumstance an update to any column requires rewriting the whole row (not just the column).
You can still accomplish this I would just be looking to a slightly smarter tool for it..
PL/Perl
PL/v8
Here is an example with plperl,
CREATE LANGUAGE plperl;
CREATE OR REPLACE FUNCTION perl_dynamic_eval_regexp_replace( IN str text, IN pattern text, IN replacementPerl text, OUT text )
STRICT
AS $BODY$
my ($input, $pattern, $replacement) = #_;
$input =~ s/$pattern/eval $replacement/ge;
return $input;
$BODY$
LANGUAGE plperl
VOLATILE;
SELECT perl_dynamic_eval_regexp_replace(
'123, "name", ignored~me, "Beer & Cheese", pi=3.14',
'"(.+?)"',
$$uc("$1")$$
);

Edit text value in Postgresql

I have a text column which holds a json with very long values - actually HTML code.
{"first_key" : "a very long html", "second_key" : "another very long html"}
How can I easily delete the second_key and its vale?
You could use regex_replace, and hope that the second html doesn't contain a } character:
update MY_TABLE set text_column = regex_replace(text_column, ', "second_key": ".*\}"', '')
where my_column_id = '<whatever>';
You will have to tweak your regex to make this work. You can test it by doing a select with the same expression to see what you get.

Using patterns in REPLACE

I need to find and replace an expression within a dynamic query. I have a subset of a where condition in string type like
'fieldA=23 OR field_1=300 OR fieldB=4'
What I need is to find a way to detect expression field_1=300 within the string and replace it while retaining the expression field_1=300.
I can do the detection part using CHARINDEX or PATINDEX but I'm not able to figure out how to use the patterns in the REPLACE function and how to get the value of the field_1 parameter.
Thanks in advance.
I'm not entirely clear on what you're trying to acheieve (e.g. what are you wanting to replace "field_1=300" with, and is it the exact string "field_1=300" that you're looking for, or just the field name, i.e. "field_1"?).
Also, could you paste in the code you've written so far?
Here's a simple script which will extract the current value of a given field name:
DECLARE #str VARCHAR(100),
#str_tmp VARCHAR(100),
#field_pattern VARCHAR(10),
#field_val INT;
SET #str = 'fieldA=23 OR field_1=300 OR fieldB=4';
SET #field_pattern = 'field_1='
-- This part will extract the current value assigned to the "#field_pattern" field
IF CHARINDEX(#field_pattern, #str) > 0
BEGIN
SELECT #str_tmp = SUBSTRING(#str,
CHARINDEX(#field_pattern, #str) + LEN(#field_pattern),
LEN(#str)
);
SELECT #field_val = CAST(SUBSTRING(#str_tmp, 1, CHARINDEX(' ', #str_tmp)-1) AS INT);
END
PRINT #field_val
If you want to replace the value itself (e.g. replacing "300" in this case with "600"), then you could add something like this:
DECLARE #new_val INT;
SET #new_val = 600;
SET #str = REPLACE(#str, (#field_pattern+CAST(#field_val AS VARCHAR)), (#field_pattern+CAST(#new_val AS VARCHAR)));
PRINT #str;
Which would give you "fieldA=23 OR field_1=600 OR fieldB=4".
Cheers,
Dave

Terminal rule ID not matching valid values for ID

I'm trying to define a rule where one element is the perfect candidate for the common terminal rule ID. When I launch the editor to test with sample code, the ID rule is not matched for the string "ABC":
Define : ABC : Holder_1
I get "mismatched input 'ABC' expecting RULE_ID".
Is there something in my grammar conflicting with the ID rule to cause this error?
This is my grammar file:
grammar com.testco.Test with org.eclipse.xtext.common.Terminals
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate defwiz "http://www.testco.com/Test"
Define_Holder:
'Definition' ':' holder_name=ID ':' holder_number=HOLDER_NUMBER (':' attribute=define_attr)? (':' pad=holder_pad)?
;
holder_pad:
HEX
;
Type:
TYPE_TERM ':' type_value=TYPE_VAL
;
//***************** TERMINALS *****************
terminal TYPE_TERM:
'Type_' INT+
;
terminal PROFILE:
(PROFILE_ID)(PROFILE_ID)'.'(PROFILE_ID)(PROFILE_ID)
;
terminal HOLDER_NUMBER returns ecore:: EString:
'Holder_' INT+;
terminal HEX returns ecore:: EString :
('0'..'9'|'A'..'F')
;
terminal PROFILE_ID : '^'?('a'..'z'|'A'..'Z') ('a'..'z'|'A'..'Z'|'0'..'9')*;
//***************** ENUMS *****************
enum define_attr:
BINARY='Binary' |
SCRAMBLE='Scramble' |
FORCESIZE='ForceSize' |
FIXEDSIZE='FixedSize'
;
Your rule PROFILE_ID shadows the ID rule for almost every case (except for the underscore).
Yes, it's likely that lexer scans ABC as HEX terminal. Try to define the latter, for example, as follows:
terminal HEX returns ecore:: EString :
'0x' ('0'..'9'|'A'..'F')
;

replace string with split_part function

I want to replace the first word before delimeter ' ,' with ' 0, the first word ')
select replace('tab,graph,map', split_part('tab,graph', ',', 1) like 'tab','0, tab')
ERROR: function replace(unknown, boolean, unknown) does not exist
LINE 1: select replace('tab,graph,map', split_part('tab,graph', ',',...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
The replace function replaces all occurrences of the string so you have to make sure the string to replace is unique or use something else. However, regexp_replace only replaces the first occurrence by default so you can use that; your question is a little unclear about what the expected output is but maybe this is is what you're looking for:
=> select regexp_replace('tab,graph,map', ',', '0,');
regexp_replace
----------------
tab0,graph,map
Or this one:
=> select regexp_replace('tab,graph,map', 'tab,', '0,');
regexp_replace
----------------
0,graph,map
Or maybe even this:
=> select regexp_replace('tab,graph,map', 'tab,', '0,,');
regexp_replace
----------------
0,,graph,map
you need to cast, since the function expects replace(text, text, text) and does not know how to handle your literal strings calling them unknown...
cast('tab,graph,map' AS text)
also the 2nd param is a LIKE comparison ? which returns boolean, but the function replace expects it to be the delimiter.
CAST(split_part('tab,graph', ',', 1) AS text)
finally the last param (same problem as the first)
cast('0, tab' AS text)
of course if you really just want to prepend '0, ' to your string, 'tab,graph,map' you could just do that...
SELECT '0, ' || 'tab,graph,map' ;