From b63622abab4e4754941e52c1d49f95ec1c54fd28 Mon Sep 17 00:00:00 2001
From: Niklas Fors <niklas.fors@cs.lth.se>
Date: Tue, 3 Jul 2018 13:38:20 +0200
Subject: [PATCH] Add semantic analysis

---
 build.xml                                     |  8 +--
 spec/jastadd/Analysis.jrag                    | 69 ++++++++++++++++++-
 spec/jastadd/Errors.jrag                      | 27 ++++++--
 spec/jastadd/RelAst.ast                       | 12 ++--
 spec/parser/RelAstBase.parser                 | 16 ++---
 .../org/jastadd/relast/compiler/Compiler.java |  6 +-
 6 files changed, 107 insertions(+), 31 deletions(-)

diff --git a/build.xml b/build.xml
index 7dad026..a35cb94 100755
--- a/build.xml
+++ b/build.xml
@@ -1,6 +1,5 @@
 <project name="RelAstCompiler" default="build" basedir=".">
 	<property name="srcdir" value="${basedir}/src" />
-	<property name="resourcedir" value="${srcdir}/resource" />
 	<property name="gendir" value="${srcdir}/generated" />
 	<property name="bindir" value="${basedir}/ant-bin" />
 	<property name="docdir" value="${basedir}/doc" />
@@ -43,9 +42,6 @@
 			target="8"
 			source="8"
 			/>
-		<copy todir="${bindir}/">
-			<fileset dir="${resourcedir}"/>
-		</copy>
 	</target>
 
 	<!-- generate compiler source files -->
@@ -93,7 +89,6 @@
 		<delete file="${jarfile}" />
 		<delete>
 			<fileset dir="." includes="**/*.class" excludes="bin/" />
-			<fileset dir="testfiles/code_generation/" includes="*.c *.executable *.out"/>
 		</delete>
 	</target>
 	
@@ -118,9 +113,8 @@
 
 	<target name="jar" depends="build">
 		<jar destfile="${jarfile}">
-			<fileset dir="${bindir}" includes="**/*.class,resource/" excludes="org/jastadd/relast/tests/*" />
+			<fileset dir="${bindir}" includes="**/*.class" excludes="org/jastadd/relast/tests/*" />
 			<fileset dir="${srcdir}/java" includes="**/*.java" excludes="org/jastadd/relast/tests/*" />
-			<fileset dir="${resourcedir}" includes="**" />
 			<fileset dir="${gendir}" includes="**/*.java" />
 			<zipfileset includes="**/*.class" src="${tools}/beaver-rt.jar"/>
 			<manifest>
diff --git a/spec/jastadd/Analysis.jrag b/spec/jastadd/Analysis.jrag
index 8aa8502..b7b0b8c 100644
--- a/spec/jastadd/Analysis.jrag
+++ b/spec/jastadd/Analysis.jrag
@@ -1,6 +1,71 @@
 import java.util.*;
 
 
-aspect Analysis {
+aspect TypeAnalysis {
+	syn TypeDecl TypeUse.decl() = lookupType(getID());
+	inh TypeDecl TypeUse.lookupType(String name);
+	eq Program.getChild().lookupType(String name) {
+		for (TypeDecl td: getTypeDecls()) {
+			if (td.getID().equals(name)) {
+				return td;
+			}
+		}
+		return null;
+	}
+	syn boolean TypeDecl.isAlreadyDeclared()
+		= lookupType(getID()) != this;
+	inh TypeDecl TypeDecl.lookupType(String name);
+}
 
-}
\ No newline at end of file
+aspect ComponentAnalysis {
+	syn String Component.name() {
+		if (!getID().isEmpty()) {
+			return getID();
+		}
+		return otherRelationSideName();
+	}
+	inh String Component.otherRelationSideName();
+	eq Relation.getLeft().otherRelationSideName()
+		= getRight().getTypeUse().getID();
+	eq Relation.getRight().otherRelationSideName()
+		= getLeft().getTypeUse().getID();
+	eq Program.getChild().otherRelationSideName()
+		= "";
+
+	syn TypeDecl Component.typeDecl() = enclosingTypeDecl();
+	eq RelationComponent.typeDecl() = getTypeUse().decl();
+	inh TypeDecl Component.enclosingTypeDecl();
+	eq TypeDecl.getChild().enclosingTypeDecl() = this;
+	eq Program.getChild().enclosingTypeDecl() = null;
+
+	syn boolean Component.isAlreadyDeclared()
+		= lookupComponent(typeDecl(), name()) != this;
+	inh Component Component.lookupComponent(TypeDecl td, String name);
+	eq Program.getChild().lookupComponent(TypeDecl td, String name) {
+		if (td != null) {
+			for (Component c: td.getComponents()) {
+				if (c.name().equals(name)) {
+					return c;
+				}
+			}
+		}
+		for (Relation r: getRelations()) {
+			if (r.getLeft().typeDecl() == td && r.getLeft().name().equals(name)) {
+				return r.getLeft();
+			}
+			if (r.getRight().typeDecl() == td && r.getRight().name().equals(name)) {
+				return r.getRight();
+			}
+		}
+		return null;
+	}
+}
+
+aspect Utils {
+	public String TypeUse.toString() {
+		return getID();
+	}
+	public String TypeDecl.toString() {
+		return getID();
+	}
+}
diff --git a/spec/jastadd/Errors.jrag b/spec/jastadd/Errors.jrag
index 788a383..a997303 100644
--- a/spec/jastadd/Errors.jrag
+++ b/spec/jastadd/Errors.jrag
@@ -3,14 +3,31 @@ import java.util.TreeSet;
 import java.util.LinkedList;
 
 aspect Errors {
-//	coll Set<ErrorMessage> Program.errors()
-//		[new TreeSet<ErrorMessage>()]
-//		root Program;
+	coll Set<ErrorMessage> Program.errors()
+		[new TreeSet<ErrorMessage>()]
+		root Program;
+
+	TypeUse contributes error("Type '" + getID() + "' not found")
+		when decl() == null && !isToken()
+		to Program.errors();
+
+	TypeDecl contributes error("Type '" + getID() + "' is already declared")
+		when isAlreadyDeclared()
+		to Program.errors();
+
+	Component contributes error("Component '" + name()
+			+ "' is already declared for type '" + typeDecl() + "'")
+		when isAlreadyDeclared()
+		to Program.errors();
 }
 
 aspect HelpAttributes {
-//	inh Program ASTNode.program();
-//	eq Program.getChild().program() = this;
+	inh Program ASTNode.program();
+	eq Program.getChild().program() = this;
+
+	inh boolean TypeUse.isToken();
+	eq Program.getChild().isToken() = false;
+	eq TokenComponent.getTypeUse().isToken() = true;
 }
 
 aspect ErrorMessage {
diff --git a/spec/jastadd/RelAst.ast b/spec/jastadd/RelAst.ast
index cf320aa..82bf011 100644
--- a/spec/jastadd/RelAst.ast
+++ b/spec/jastadd/RelAst.ast
@@ -9,13 +9,11 @@ OptComponent : Component;
 
 TypeUse ::= <ID>;
 
-Relation ::= Left:RelationSide Direction Right:RelationSide;
-abstract RelationSide ::= TypeUse <ID>;
-OneRelationSide : RelationSide;
-OptionalRelationSide : RelationSide;
-ManyRelationSide : RelationSide;
-
-
+Relation ::= Left:RelationComponent Direction Right:RelationComponent;
+abstract RelationComponent : Component;
+OneRelationComponent : RelationComponent;
+OptionalRelationComponent : RelationComponent;
+ManyRelationComponent : RelationComponent;
 abstract Direction;
 RightDirection : Direction;
 Bidirectional : Direction;
\ No newline at end of file
diff --git a/spec/parser/RelAstBase.parser b/spec/parser/RelAstBase.parser
index dac3519..291055d 100644
--- a/spec/parser/RelAstBase.parser
+++ b/spec/parser/RelAstBase.parser
@@ -54,20 +54,20 @@ List relations =
 	;
 
 Relation relation =
-	RELATION relation_side.l direction relation_side.r SCOL 
+	RELATION relation_comp.l direction relation_comp.r SCOL
 	{: return new Relation(l, direction, r); :}
 	;
 
-RelationSide relation_side =
+RelationComponent relation_comp =
 	// One
-	type_use.u DOT ID {: return new OneRelationSide(u, ID); :}
-	| type_use.u {: return new OneRelationSide(u, ""); :}
+	type_use.u DOT ID {: return new OneRelationComponent(ID, u); :}
+	| type_use.u {: return new OneRelationComponent("", u); :}
 	// Optional
-	| LBRACKET type_use.u DOT ID RBRACKET {: return new OptionalRelationSide(u, ID); :}
-	| LBRACKET type_use.u RBRACKET {: return new OptionalRelationSide(u, ""); :}
+	| LBRACKET type_use.u DOT ID RBRACKET {: return new OptionalRelationComponent(ID, u); :}
+	| LBRACKET type_use.u RBRACKET {: return new OptionalRelationComponent("", u); :}
 	// Many
-	| type_use.u STAR DOT ID {: return new ManyRelationSide(u, ID); :}
-	| type_use.u STAR {: return new ManyRelationSide(u, ""); :}
+	| type_use.u STAR DOT ID {: return new ManyRelationComponent(ID, u); :}
+	| type_use.u STAR {: return new ManyRelationComponent("", u); :}
 	;
 
 Direction direction =
diff --git a/src/java/org/jastadd/relast/compiler/Compiler.java b/src/java/org/jastadd/relast/compiler/Compiler.java
index 397ee2a..e5692ee 100644
--- a/src/java/org/jastadd/relast/compiler/Compiler.java
+++ b/src/java/org/jastadd/relast/compiler/Compiler.java
@@ -33,14 +33,16 @@ public class Compiler {
 
 		Program p = parseProgram(commandLine.getArguments().get(0));
 
-		System.out.println(p.dumpTree());
-		/*if (!p.errors().isEmpty()) {
+		if (!p.errors().isEmpty()) {
 			System.err.println("Errors:");
 			for (ErrorMessage e: p.errors()) {
 				System.err.println(e);
 			}
 			System.exit(1);
 		} else {
+			System.out.println(p.dumpTree());
+		}
+/*		} else {
 			if (optionPrintDot.isSet()) {
 				System.out.println(p.genDot());
 			} else if (optionFlatPrettyPrint.isSet()) {
-- 
GitLab