From 83ee58cb2f40c40e7e328b390a046db3fea7219c Mon Sep 17 00:00:00 2001
From: Niklas Fors <niklas.fors@cs.lth.se>
Date: Thu, 5 Jul 2018 15:32:59 +0200
Subject: [PATCH] Support parameterized types in intrinsic attributes

---
 spec/jastadd/Analysis.jrag    | 19 ++++++++++++++--
 spec/jastadd/RelAst.ast       | 17 ++++++++------
 spec/parser/RelAstBase.parser | 42 ++++++++++++++++++++++-------------
 spec/scanner/RelAst.flex      |  3 ++-
 test/.gitignore               |  2 ++
 test/Makefile                 |  7 ++++--
 6 files changed, 63 insertions(+), 27 deletions(-)

diff --git a/spec/jastadd/Analysis.jrag b/spec/jastadd/Analysis.jrag
index f71c225..223a1fb 100644
--- a/spec/jastadd/Analysis.jrag
+++ b/spec/jastadd/Analysis.jrag
@@ -2,6 +2,8 @@ import java.util.*;
 
 
 aspect TypeAnalysis {
+	public abstract TypeUse Component.getTypeUse();
+
 	syn TypeDecl TypeUse.decl() = lookupType(getID());
 	inh TypeDecl TypeUse.lookupType(String name);
 	eq Program.getChild().lookupType(String name) {
@@ -37,7 +39,7 @@ aspect ComponentAnalysis {
 	eq Relation.getLeft().otherSide() = getRight();
 	eq Relation.getRight().otherSide() = getLeft();
 	eq Program.getChild().otherSide() = null;
-	
+
 	syn TypeDecl RelationComponent.ofTypeDecl() = otherSide().toTypeDecl();
 
 	syn boolean Component.isAlreadyDeclared()
@@ -102,9 +104,22 @@ aspect Constructors {
 }
 
 aspect Utils {
-	public String TypeUse.toString() {
+	public String SimpleTypeUse.toString() {
 		return getID();
 	}
+	public String ParameterizedTypeUse.toString() {
+		StringBuilder sb = new StringBuilder();
+		sb.append(getID()).append("<");
+		int i = 0;
+		for (TypeUse u: getTypeUses()) {
+			sb.append(u.toString());
+			if (++i < getNumTypeUse()) {
+				sb.append(", ");
+			}
+		}
+		sb.append(">");
+		return sb.toString();
+	}
 	public String TypeDecl.toString() {
 		return getID();
 	}
diff --git a/spec/jastadd/RelAst.ast b/spec/jastadd/RelAst.ast
index 82bf011..3a7116e 100644
--- a/spec/jastadd/RelAst.ast
+++ b/spec/jastadd/RelAst.ast
@@ -1,16 +1,19 @@
 Program ::= TypeDecl* Relation*;
 TypeDecl ::= <ID> <Abstract:boolean> [Super:TypeUse] Component*;
 
-abstract Component ::= <ID> TypeUse;
-NormalComponent : Component;
-ListComponent : Component;
-TokenComponent : Component;
-OptComponent : Component;
+abstract Component ::= <ID>;
+abstract SimpleTypeComponent : Component ::= TypeUse:SimpleTypeUse;
+NormalComponent : SimpleTypeComponent;
+ListComponent : SimpleTypeComponent;
+OptComponent : SimpleTypeComponent;
+TokenComponent : Component ::= TypeUse;
 
-TypeUse ::= <ID>;
+abstract TypeUse ::= <ID>;
+SimpleTypeUse : TypeUse;
+ParameterizedTypeUse : TypeUse ::= TypeUse*;
 
 Relation ::= Left:RelationComponent Direction Right:RelationComponent;
-abstract RelationComponent : Component;
+abstract RelationComponent : SimpleTypeComponent;
 OneRelationComponent : RelationComponent;
 OptionalRelationComponent : RelationComponent;
 ManyRelationComponent : RelationComponent;
diff --git a/spec/parser/RelAstBase.parser b/spec/parser/RelAstBase.parser
index 7c12f1f..6b99a76 100644
--- a/spec/parser/RelAstBase.parser
+++ b/spec/parser/RelAstBase.parser
@@ -17,11 +17,23 @@ TypeDecl type_decl =
 
 Opt type_decl_super =
 	/* empty */ {: return new Opt(); :}
-	| COL type_use.u {: return new Opt(u); :}
+	| COL s_type_use.u {: return new Opt(u); :}
+	;
+
+SimpleTypeUse s_type_use =
+	ID {: return new SimpleTypeUse(ID); :}
 	;
 
 TypeUse type_use =
-	ID {: return new TypeUse(ID); :}
+	s_type_use.u {: return u; :}
+	| parameterized_type_use.p {: return p; :}
+	;
+ParameterizedTypeUse parameterized_type_use =
+	ID LT type_use_list.l GT {: return new ParameterizedTypeUse(ID, l); :}
+	;
+List type_use_list =
+	type_use.u {: return new List().add(u); :}
+	| type_use_list.l COMMA type_use.u {: return l.add(u); :}
 	;
 
 List components_opt =
@@ -35,17 +47,17 @@ List components =
 	;
 
 Component component =
-	ID COL type_use.u {: return new NormalComponent(ID, u); :}
-	| type_use.u {: return new NormalComponent(u.getID(), u); :}
+	ID COL s_type_use.u {: return new NormalComponent(ID, u); :}
+	| s_type_use.u {: return new NormalComponent(u.getID(), u); :}
 	// List
-	| ID COL type_use.u STAR {: return new ListComponent(ID, u); :}
-	| type_use.u STAR {: return new ListComponent(u.getID(), u); :}
+	| ID COL s_type_use.u STAR {: return new ListComponent(ID, u); :}
+	| s_type_use.u STAR {: return new ListComponent(u.getID(), u); :}
 	// Opt
-	| ID COL type_use.u QUESTION_MARK {: return new OptComponent(ID, u); :}
-	| type_use.u QUESTION_MARK {: return new OptComponent(u.getID(), u); :}
+	| ID COL s_type_use.u QUESTION_MARK {: return new OptComponent(ID, u); :}
+	| s_type_use.u QUESTION_MARK {: return new OptComponent(u.getID(), u); :}
 	// Token
 	| LT ID COL type_use.u GT {: return new TokenComponent(ID, u); :}
-	| LT ID GT {: return new TokenComponent(ID, new TypeUse("String")); :}
+	| LT ID GT {: return new TokenComponent(ID, new SimpleTypeUse("String")); :}
 	;
 
 List relations =
@@ -60,14 +72,14 @@ Relation relation =
 
 RelationComponent relation_comp =
 	// One
-	type_use.u DOT ID {: return new OneRelationComponent(ID, u); :}
-	| type_use.u {: return new OneRelationComponent("", u); :}
+	s_type_use.u DOT ID {: return new OneRelationComponent(ID, u); :}
+	| s_type_use.u {: return new OneRelationComponent("", u); :}
 	// Optional
-	| type_use.u DOT ID QUESTION_MARK {: return new OptionalRelationComponent(ID, u); :}
-	| type_use.u QUESTION_MARK {: return new OptionalRelationComponent("", u); :}
+	| s_type_use.u DOT ID QUESTION_MARK {: return new OptionalRelationComponent(ID, u); :}
+	| s_type_use.u QUESTION_MARK {: return new OptionalRelationComponent("", u); :}
 	// Many
-	| type_use.u DOT ID STAR {: return new ManyRelationComponent(ID, u); :}
-	| type_use.u STAR {: return new ManyRelationComponent("", u); :}
+	| s_type_use.u DOT ID STAR {: return new ManyRelationComponent(ID, u); :}
+	| s_type_use.u STAR {: return new ManyRelationComponent("", u); :}
 	;
 
 Direction direction =
diff --git a/spec/scanner/RelAst.flex b/spec/scanner/RelAst.flex
index 1e40019..44ec2a2 100644
--- a/spec/scanner/RelAst.flex
+++ b/spec/scanner/RelAst.flex
@@ -40,7 +40,7 @@ TraditionalComment   = "/*" [^*] ~"*/" | "/*" "*"+ "/"
 EndOfLineComment = "//" [^\n|\r|\r\n]*
 Comment = {TraditionalComment} | {EndOfLineComment}
 
-ID = [a-zA-Z$][a-zA-Z0-9$_]*
+ID = [a-zA-Z$_][a-zA-Z0-9$_]*
 
 %state STRING
 
@@ -57,6 +57,7 @@ ID = [a-zA-Z$][a-zA-Z0-9$_]*
 	"::="			{ return sym(Terminals.ASSIGN); }
 	"*"				{ return sym(Terminals.STAR); }
 	"."				{ return sym(Terminals.DOT); }
+	","				{ return sym(Terminals.COMMA); }
 	"<"				{ return sym(Terminals.LT); }
 	">"				{ return sym(Terminals.GT); }
 	"?"				{ return sym(Terminals.QUESTION_MARK); }
diff --git a/test/.gitignore b/test/.gitignore
index f09d75c..12f898e 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -1,3 +1,5 @@
 /AST/*
 /AllGen.ast
 /AllGen.jadd
+/AllGenGen.ast
+/AllGenGen.jadd
diff --git a/test/Makefile b/test/Makefile
index d30d502..4f66686 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,8 +1,11 @@
-all: compile run
+all: compile run check-idempotent
 compile:
 	(cd .. && ant jar)
 	java -jar ../relast-compiler.jar All.relast --file
 	java -jar ../tools/jastadd2.jar --package=AST AllGen.ast AllGen.jadd Utils.jadd
 run:
 	javac AST/*.java Test.java
-	java Test
\ No newline at end of file
+	java Test
+check-idempotent:
+	java -jar ../relast-compiler.jar AllGen.ast --file
+	diff AllGen.ast AllGenGen.ast
-- 
GitLab