Say I need some very special multiplication operator. It may be implemented in following macro:
macro #<<!(op1, op2)
{
<[ ( $op1 * $op2 ) ]>
}
And I can use it like
def val = 2 <<! 3
And its work.
But what I really want is some 'english'-like operator for the DSL Im developing now:
macro #multiply(op1, op2)
{
<[ ( $op1 * $op2 ) ]>
}
and if I try to use it like
def val = 2 multiply 3
compiler fails with 'expected ;' error
What is the problem? How can I implement this infix-format macro?
Straight from the compiler source code:
namespace Nemerle.English
{
[assembly: Nemerle.Internal.OperatorAttribute ("Nemerle.English", "and", false, 160, 161)]
[assembly: Nemerle.Internal.OperatorAttribute ("Nemerle.English", "or", false, 150, 151)]
[assembly: Nemerle.Internal.OperatorAttribute ("Nemerle.English", "not", true, 181, 180)]
macro #and (e1, e2) {
<[ $e1 && $e2 ]>
}
macro #or (e1, e2) {
<[ $e1 || $e2 ]>
}
macro #not (e) {
<[ ! $e ]>
}
You need to sprinkle OperatorAttributes around and it will work. Btw, OperatorAttribute is defined as follows:
public class OperatorAttribute : NemerleAttribute
{
public mutable env : string;
public mutable name : string;
public mutable IsUnary : bool;
public mutable left : int;
public mutable right : int;
}
As usually, I found answer sooner than comunity respond :)
So, solution is to simply use special assemply level attribute which specifies the macro as binary operator:
namespace TestMacroLib
{
[assembly: Nemerle.Internal.OperatorAttribute ("TestMacroLib", "multiply", false, 160, 161)]
public macro multiply(op1, op2)
{
<[ ( $op1 * $op2 ) ]>
}
}
Related
I have below input to be parsed:-
([LANGUAGE] IN ("Arabic", "Dutch") AND [Content Series] IN ("The Walking Dead") AND [PUBLISHER_NAME] IN ("Yahoo Search", "Yahoo! NAR") )
OR
([LANGUAGE] IN ("English") AND [PUBLISHER_NAME] IN ("Aol News", "Microsoft-Bing!") )
Basically the inputs have 2 groups separated by 'OR'.Both groups has several base exp(targetEntities) separated by AND. So each group has list of target entities.
Grammar file:
grammar Exp;
options {
language = Java;
}
start
: def EOF
;
def : (AND? base)+
| (OR? '(' def ')')*
;
base : key operator values ;
key : LSQR ID RSQR ;
values : '(' VALUE (',' VALUE)* ')' ;
operator : IN
| NIN
;
VALUE: '"' .*? '"' ;
AND : 'AND' ;
OR : 'OR' ;
NOT : 'not' ;
EQ : '=' ;
COMMA : ',' ;
SEMI : ';' ;
IN : 'IN' ;
NIN : 'NOT_IN' ;
LSQR : '[' ;
RSQR : ']' ;
INT : [0-9]+ ;
ID: [a-zA-Z_][a-zA-Z_0-9-!]* ;
WS: [\t\n\r\f ]+ -> skip ;
Below is the listener and parser-
#Component
#NoArgsConstructor
public class ANTLRTargetingExpressionParser {`
static List<Group> groupList = new ArrayList<>();
public String entityOperator;
public static class ExpMapper extends ExpBaseListener {
TargetEntity targetEntity;
Group group;
List<TargetEntity> targetEntities;
private static int inc = 1;
#Override
public void exitDef(ExpParser.DefContext ctx) {
group.setTargets(targetEntities);
groupList.add(group);
super.exitDef(ctx);
}
#Override
public void exitValues(ExpParser.ValuesContext ctx) {
targetEntity.setValues(
Arrays.asList(
Arrays.toString(ctx.VALUE().stream().collect(Collectors.toSet()).toArray())));
super.exitValues(ctx);
targetEntities.add(targetEntity);
}
#Override
public void exitOperator(ExpParser.OperatorContext ctx) {
targetEntity.setOperator(ctx.getText());
super.exitOperator(ctx);
}
#Override
public void exitKey(ExpParser.KeyContext ctx) {
targetEntity = new TargetEntity();
ctx.getParent();
targetEntity.setEntity(ctx.ID().getText());
super.exitKey(ctx);
}
#Override
public void enterDef(ExpParser.DefContext ctx) {
group = new Group();
targetEntities = new ArrayList<>();
super.enterDef(ctx);
}
}
public List<Group> parse(String expression) {`
ANTLRInputStream in = new ANTLRInputStream(expression);
ExpLexer lexer = new ExpLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ExpParser parser = new ExpParser(tokens);
parser.setBuildParseTree(true); // tell ANTLR to build a parse tree
ParseTree tree = parser.def();
/** Create standard walker. */
ParseTreeWalker walker = new ParseTreeWalker();
System.out.println(tree.toStringTree(parser));
ExpMapper mapper = new ExpMapper();
walker.walk(mapper, tree);
return groupList;
}
}
Output:-
[Group(targets=[{LANGUAGE, IN, [["Dutch", "Arabic"]]}, {Content_Series, IN, [["The Walking Dead"]]}, {PUBLISHER_NAME, IN, [["Yahoo Search", "Yahoo! NAR"]]}]),
Group(targets=[{LANGUAGE, IN, [["English"]]}, {PUBLISHER_NAME, IN, [["Aol News", "Microsoft-Bing!"]]}]),
Group(targets=[{LANGUAGE, IN, [["English"]]}, {PUBLISHER_NAME, IN, [["Aol News", "Microsoft-Bing!"]]}])]
Q1:- I am getting duplicate value in the grouplist at end. Tried checking the value in ctx to stop the walker but couldnt help.
Q2:- Also how can we catch the soft exception thrown by grammar file in case of wrong input given in java.
(NOTE: It's MUCH easier to sort questions out if you ensure that the examples you provide are valid and are compilable. I had to change a few things just to get a clean parse, and there's too much missing to attempt to compile and run your code.)
That said....
def : (AND? base)+
| (OR? '(' def ')')*
;
Would normally be represented as something akin to
def: '(' def ')'
| def AND def
| def OR def
| base
;
(Note: these are not exactly equivalent. Your rule requires parentheses around defs used in an OR, but disallows them when used with AND. Those would be "odd" constraints, so I'm not sure if you intended that.)
You'll notice here that it's clear that a def can contain other defs. This is also true in your rule for (but only as the second half of an OR type.
It can be really useful to use a plugin or the -gui option of the antler tool, to see a visual representation of your tree. (Both IntelliJ, and VS Code have good plugins available for this). With that visualization it would have been clear that there was a def in a subtree of a def. (The information would have been the in the output of the System.out.println(tree.toStringTree(parser));, but a bit harder to notice.
This is your clue. You're getting a duplicate of the second half of your OR and this is because you'll have a nested def and, as a result, you'll exitDef twice (and add it twice in the process).
Your listener does not handle nested structures like this properly (having only a targetEntity and a group). You'll need to do something like maintaining a stack of Group instances and pushing/popping as you enter/exit (and only dealing with the top of the stack).
A few other observations:
super.enterDef(ctx);
There's no need to call the super method on your listener overrides, the default methods are empty. (Of course, it does no harm, and it can be a "safe" practice to generally call the super method when overriding.
ctx.getParent();
You didn't do anything with this parent, as a result, this doesn't do anything.
Using Antlr 4 I have a situation I am not sure how to resolve. I originally asked the question at https://groups.google.com/forum/#!topic/antlr-discussion/1yxxxAvU678 on the Antlr discussion forum. But that forum does not seem to get a lot of traffic, so I am asking again here.
I have the following grammar:
expression
: ...
| path
;
path
: ...
| dotIdentifierSequence
;
dotIdentifierSequence
: identifier (DOT identifier)*
;
The concern here is that dotIdentifierSequence can mean a number of things semantically, and not all of them are "paths". But at the moment they are all recognized as paths in the parse tree and then I need to handle them specially in my visitor.
But what I'd really like is a way to express the dotIdentifierSequence usages that are not paths into the expression rule rather than in the path rule, and still have dotIdentifierSequence in path to handle path usages.
To be clear, a dotIdentifierSequence might be any of the following:
A path - this is a SQL-like grammar and a path expression would be like a table or column reference in SQL, e.g. a.b.c
A Java class name - e.g. com.acme.SomeJavaType
A static Java field reference - e.g. com.acme.SomeJavaType.SOME_FIELD
A Java enum value reference - e.g. com.acme.Gender.MALE
The idea is that during visitation "dotIdentifierSequence as a path" resolves as a very different type from the other usages.
Any idea how I can do this?
The issue here is that you're trying to make a distinction between "paths" while being created in the parser. Constructing paths inside the lexer would be easier (pseudo code follows):
grammar T;
tokens {
JAVA_TYPE_PATH,
JAVA_FIELD_PATH
}
// parser rules
PATH
: IDENTIFIER ('.' IDENTIFIER)*
{
String s = getText();
if (s is a Java class) {
setType(JAVA_TYPE_PATH);
} else if (s is a Java field) {
setType(JAVA_FIELD_PATH);
}
}
;
fragment IDENTIFIER : [a-zA-Z_] [a-zA-Z_0-9]*;
and then in the parser you would do:
expression
: JAVA_TYPE_PATH #javaTypeExpression
| JAVA_FIELD_PATH #javaFieldExpression
| PATH #pathExpression
;
But then, of course, input like this java./*comment*/lang.String would be tokenized wrongly.
Handling it all in the parser would mean manually looking ahead in the token stream and checking if either a Java type, or field exists.
A quick demo:
grammar T;
#parser::members {
String getPathAhead() {
Token token = _input.LT(1);
if (token.getType() != IDENTIFIER) {
return null;
}
StringBuilder builder = new StringBuilder(token.getText());
// Try to collect ('.' IDENTIFIER)*
for (int stepsAhead = 2; ; stepsAhead += 2) {
Token expectedDot = _input.LT(stepsAhead);
Token expectedIdentifier = _input.LT(stepsAhead + 1);
if (expectedDot.getType() != DOT || expectedIdentifier.getType() != IDENTIFIER) {
break;
}
builder.append('.').append(expectedIdentifier.getText());
}
return builder.toString();
}
boolean javaTypeAhead() {
String path = getPathAhead();
if (path == null) {
return false;
}
try {
return Class.forName(path) != null;
} catch (Exception e) {
return false;
}
}
boolean javaFieldAhead() {
String path = getPathAhead();
if (path == null || !path.contains(".")) {
return false;
}
int lastDot = path.lastIndexOf('.');
String typeName = path.substring(0, lastDot);
String fieldName = path.substring(lastDot + 1);
try {
Class<?> clazz = Class.forName(typeName);
return clazz.getField(fieldName) != null;
} catch (Exception e) {
return false;
}
}
}
expression
: {javaTypeAhead()}? path #javaTypeExpression
| {javaFieldAhead()}? path #javaFieldExpression
| path #pathExpression
;
path
: dotIdentifierSequence
;
dotIdentifierSequence
: IDENTIFIER (DOT IDENTIFIER)*
;
IDENTIFIER
: [a-zA-Z_] [a-zA-Z_0-9]*
;
DOT
: '.'
;
which can be tested with the following class:
package tl.antlr4;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
public class Main {
public static void main(String[] args) {
String[] tests = {
"mu",
"tl.antlr4.The",
"java.lang.String",
"foo.bar.Baz",
"tl.antlr4.The.answer",
"tl.antlr4.The.ANSWER"
};
for (String test : tests) {
TLexer lexer = new TLexer(new ANTLRInputStream(test));
TParser parser = new TParser(new CommonTokenStream(lexer));
ParseTreeWalker.DEFAULT.walk(new TestListener(), parser.expression());
}
}
}
class TestListener extends TBaseListener {
#Override
public void enterJavaTypeExpression(#NotNull TParser.JavaTypeExpressionContext ctx) {
System.out.println("JavaTypeExpression -> " + ctx.getText());
}
#Override
public void enterJavaFieldExpression(#NotNull TParser.JavaFieldExpressionContext ctx) {
System.out.println("JavaFieldExpression -> " + ctx.getText());
}
#Override
public void enterPathExpression(#NotNull TParser.PathExpressionContext ctx) {
System.out.println("PathExpression -> " + ctx.getText());
}
}
class The {
public static final int ANSWER = 42;
}
which would print the following to the console:
PathExpression -> mu
JavaTypeExpression -> tl.antlr4.The
JavaTypeExpression -> java.lang.String
PathExpression -> foo.bar.Baz
PathExpression -> tl.antlr4.The.answer
JavaFieldExpression -> tl.antlr4.The.ANSWER
I am writing my first D program, and trying to understand how to implement an associative array. The issue that keeps coming up is that if i create an array like:
import std.stdio;
import std.string;
import std.array;
void main(string[] args) {
int[string] arr = ["first" : 1, "second" : 2];
}
everything compiles fine. but if i try and move arr outside of main--into a struct, i get an error saying: Error: non-constant expression.
this throws the error:
import std.stdio;
import std.string;
import std.array;
struct foo {
int[string] arr = ["first" : 1, "second" : 2];
}
void main(string[] args)
{ /* do stuff with foo */ }
I'm sure this is a super simple fix, but this is my first attempt at D.
This limitation comes from the fact that symbols in D modules are not ordered but exist "in parallel". Which is generally a good thing because:
compiler can possibly do semantic analysis in parallel
you don't need explicit forward declarations (like in C) to use symbol declared later in the module
With that in mind, consider this code (global scope):
int x;
int foo() { return ++x; }
int y1 = foo();
int y2 = foo();
If using run-time code was allowed for initializers, values of y1 and y2 would depend on order of evaluation which is not defined in general - all globals are "equal".
But for local function variables there is no such problem - they are placed on stack and thus order of evaluation is perfectly defined (it is in lexical order):
void foo()
{
int x;
int foo() { return ++x; }
int y1 = foo(); // will always be 1
int y2 = foo(); // will always be 2
}
Because of that compiler restricts you to only compile-time constants when using initializer syntax for globals or struct fields. Constructors (including module constructors) are still OK though:
int[int] x;
static this()
{
x = [ 1 : 1, 2 : 2 ];
}
AA literal may look like a proper constant but it actually needs to allocate memory from run-time heap. D is smart enough to accept some of such entities (even some classes) and put them in fixed binary memory section but AA may be extended so proper dynamic heap is necessary.
Also please note that struct in D can't have default constructor:
struct foo
{
int[string] arr;
// this won't work:
this() { this.arr = ["first" : 1, "second" : 2]; }
}
// need class instead
class boo
{
int[string] arr;
// fine:
this() { this.arr = ["first" : 1, "second" : 2]; }
}
Something like this will work.
struct Foo{
int[string] arr;
}
void main(){
Foo foo = Foo(["first" : 1, "second" : 2]);
}
I have the following code :
class Test {
static function main() {
trace("Haxe is great!");
var api:Api = new Api();
api.doAdd(1,1);
}
}
class Api {
public function new(){}
public function doAdd( x : Int, y : Int ) {
trace( x + y );
}
public function doAdd( x : Int, y : Int , z : Int) {
trace( x + y + z);
}
}
Here is a link to a try Haxe code
If I try to compile this code, I get an error : ```Duplicate class field declaration : doAdd````
My question is, is there anyway to have two methods with differents signatures in haxe ?
On the Java and C# targets, the following works:
#:overload
public function doAdd(x:Int, y:Int) {
trace(x + y);
}
#:overload
public function doAdd(x:Int, y:Int, z:Int) {
trace(x + y + z);
}
On other targets, the syntax for #:overload is a bit different and only works for externs as far as I understand it. There's an example in this thread.
I am using GroovyShell (2.1.7) to dynamically evaluate some Groovy code that I have stored off as a string.
GroovyShell shell = magicallyInstantiateAndBindGroovyShell();
The above method takes care of instantiating the shell, and binding all the required variables to it. Since I believe this is a syntax error, I won't clutter this question with all the variables the shell is being bound with, and what the code I'm trying to evaluate is actually doing. If it turns out that I need to add any more info to the question to help solve my problem, I'll happily oblige!
I then have a string of Groovy code that I am trying to evaluate:
com.me.myorg.myapp.ExpressionUtils.metaClass.filterMetadata = {
com.me.myorg.myapp.model.WidgetVO widget, List<String> properties ->
WidgetVO toReturn = new WidgetVO();
toReturn.setFizz(widget.getFizz());
if(widget.getBuzz().equalsIgnoreCase("BIMDER")) {
toReturn.setMode(widget.getMode());
}
for(String property : properties) {
if("some.prop".equals(property)) {
Preconditions.checkNotNull(widget.getDescriptions());
toReturn.setDescriptions(new ArrayList<DescriptionVO>());
DescriptionVO description = widget.getDescriptions().get(0);
toReturn.getDescriptions().add(description);
} else if("another.prop".equals(property)) {
Preconditions.checkNotNull(widget.getTitles().get(0));
toReturn.setTitles(new ArrayList<TitleVO>());
TitleVO title = widget.getTitles().get(0);
toReturn.getTitles().add(title);
}
}
return toReturn;
};
Which I actually have stored off as a string variable:
String code = "com.me.myorg.myapp.ExpressionUtils.metaClass.filterMetadata = { com.me.myorg.myapp.model.WidgetVO widget, List<String> properties -> WidgetVO toReturn = new WidgetVO(); toReturn.setFizz(widget.getFizz()); if(widget.getBuzz().equalsIgnoreCase(\"BIMDER\")) { toReturn.setMode(widget.getMode()); } for(String property : properties) { if(\"some.prop\".equals(property)) { Preconditions.checkNotNull(widget.getDescriptions()); toReturn.setDescriptions(new ArrayList<DescriptionVO>()); DescriptionVO description = widget.getDescriptions().get(0); toReturn.getDescriptions().add(description); } else if(\"another.prop\".equals(property)) { Preconditions.checkNotNull(widget.getTitles().get(0)); toReturn.setTitles(new ArrayList<TitleVO>()); TitleVO title = widget.getTitles().get(0); toReturn.getTitles().add(title); } } return toReturn; };
When I run:
shell.evaluate(code);
I get the following exception:
startup failed, Script1.groovy: 1: unexpected token: for # line 1, column 294.
1 error
No signature of method: com.me.myorg.myapp.ExpressionUtils.metaClass.filterMetadata() is applicable for argument types: (com.me.myorg.myapp.model.WidgetVO, java.util.ArrayList) values: {com.me.myorg.myapp.model.WidgetVO#9427908c, ["some.prop", "another.prop"]}
Column 294 is the beginning of the for-loop... but to me, this seems like perfectly fine code. Am I forgetting a closing bracket anywhere? Some other syntax error? Where am I going awry? Thanks in advance!
You have:
if(widget.getBuzz().equalsIgnoreCase(\"BIMDER\")) { toReturn.setMode(widget.getMode()); } for(String property : properties)
You need a semicolon before the for...
Why not use a multi-line string?
String code = """com.me.myorg.myapp.ExpressionUtils.metaClass.filterMetadata = { com.me.myorg.myapp.model.WidgetVO widget, List<String> properties ->
| WidgetVO toReturn = new WidgetVO()
| toReturn.setFizz(widget.getFizz())
| if( widget.getBuzz().equalsIgnoreCase( "BIMDER" ) ) {
| toReturn.setMode(widget.getMode())
| }
| for( String property : properties ) {
| if( "some.prop" == property ) {
| Preconditions.checkNotNull( widget.descriptions )
| toReturn.descriptions = [ widget.descriptions[ 0 ] ]
| }
| else if( "another.prop" == property ) {
| Preconditions.checkNotNull( widget.titles[ 0 ] )
| toReturn.titles = [ widget.titles[ 0 ] ]
| }
| }
| toReturn
|}""".stripMargin()