From e403ff4206137e6f08874d3acae3d3fb7cf13253 Mon Sep 17 00:00:00 2001 From: Nathanael Sensfelder Date: Thu, 24 May 2018 11:12:09 +0200 Subject: Starting a HaStABeL library... --- Makefile | 81 +++++++++++ src/hastabel/Elements.java | 98 +++++++++++++ src/hastabel/LangLexer.g4 | 25 ++++ src/hastabel/LangParser.g4 | 279 ++++++++++++++++++++++++++++++++++++ src/hastabel/LogicWorld.java | 34 +++++ src/hastabel/Predicates.java | 101 +++++++++++++ src/hastabel/Template.java | 105 ++++++++++++++ src/hastabel/TemplateInstance.java | 37 +++++ src/hastabel/TemplateInstances.java | 61 ++++++++ src/hastabel/Templates.java | 63 ++++++++ src/hastabel/Types.java | 75 ++++++++++ src/hastabel/World.java | 54 +++++++ src/hastabel/lang/Element.java | 50 +++++++ src/hastabel/lang/Predicate.java | 155 ++++++++++++++++++++ src/hastabel/lang/Type.java | 100 +++++++++++++ 15 files changed, 1318 insertions(+) create mode 100644 Makefile create mode 100644 src/hastabel/Elements.java create mode 100644 src/hastabel/LangLexer.g4 create mode 100644 src/hastabel/LangParser.g4 create mode 100644 src/hastabel/LogicWorld.java create mode 100644 src/hastabel/Predicates.java create mode 100644 src/hastabel/Template.java create mode 100644 src/hastabel/TemplateInstance.java create mode 100644 src/hastabel/TemplateInstances.java create mode 100644 src/hastabel/Templates.java create mode 100644 src/hastabel/Types.java create mode 100644 src/hastabel/World.java create mode 100644 src/hastabel/lang/Element.java create mode 100644 src/hastabel/lang/Predicate.java create mode 100644 src/hastabel/lang/Type.java diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..be7a161 --- /dev/null +++ b/Makefile @@ -0,0 +1,81 @@ +## Parameters ################################################################## +SRC_DIR ?= ${CURDIR}/src/ +BIN_DIR ?= ${CURDIR}/bin/ +LIB_DIR ?= ${CURDIR}/lib/ + +TARGET ?= hastabel.jar +INSTALL_DIR ?= . + +#### Where to get the missing Jar files. +JAR_SOURCE ?= "https://noot-noot.org/tabellion/jar/" + +#### Binaries +###### JAR binary +JAR ?= jar + +###### JRE binary +JAVA ?= java + +###### JDK binary +JAVAC ?= javac + +###### ANTLR +ANTLR_JAR ?= $(LIB_DIR)/antlr-4.7-complete.jar + +##### Downloader +DOWNLOADER ?= wget + +## Parameters Sanity Check ##################################################### +ifeq ($(strip $(JAVA)),) +$(error No Java executable defined as parameter.) +endif + +ifeq ($(strip $(JAVAC)),) +$(error No Java compiler defined as parameter.) +endif + +ifeq ($(strip $(ANTLR_JAR)),) +$(error No ANTLR_JAR defined as parameter.) +endif + +## Java Config ################################################################# +CLASSPATH = "$(SRC_DIR):$(BIN_DIR):$(ANTLR_JAR)" + +## Makefile Magic ############################################################## +ANTLR_SOURCES = $(wildcard $(SRC_DIR)/hastabel/*.g4) +JAVA_SOURCES = \ + $(filter-out $(ANTLR_SOURCES:.g4=.java), \ + $(wildcard $(SRC_DIR)/hastabel/*.java) \ + )\ + $(ANTLR_SOURCES:.g4=.java) +CLASSES = $(patsubst $(SRC_DIR)/%,$(BIN_DIR)/%, $(JAVA_SOURCES:.java=.class)) + +## Makefile Rules ############################################################## +$(TARGET): $(ANTLR_JAR) $(JAVA_SOURCES) $(CLASSES) + rm -f $(TARGET) $(INSTALL_DIR)/$@ + $(JAR) cf $@ -C $(BIN_DIR) . + cp $@ $(INSTALL_DIR)/$@ + +clean: + rm -f $(filter-out $(ANTLR_SOURCES),$(wildcard $(ANTLR_SOURCES:.g4=*))) + rm -rf $(BIN_DIR)/* + rm -f $(TARGET) + +$(SRC_DIR)/hastabel/LangParser.java: $(ANTLR_SOURCES) + +# Pattern rules can be used to generate multiple target in a single action. +LangLexer%java LangParser%java: $(ANTLR_SOURCES) + $(JAVA) -jar $(ANTLR_JAR) -lib $(SRC_DIR)/hastabel/ $^ + +$(CLASSES): $(BIN_DIR)/%.class: $(SRC_DIR)/%.java $(BIN_DIR) + $(JAVAC) -cp $(CLASSPATH) -d $(BIN_DIR) $< + +%.jar: $(LIB_DIR) + echo "Attempting to download missing jar '$@'..." + cd $(LIB_DIR); $(DOWNLOADER) "$(JAR_SOURCE)/$(notdir $@)" + +$(LIB_DIR): + mkdir -p $@ + +$(BIN_DIR): + mkdir -p $@ diff --git a/src/hastabel/Elements.java b/src/hastabel/Elements.java new file mode 100644 index 0000000..0d493f9 --- /dev/null +++ b/src/hastabel/Elements.java @@ -0,0 +1,98 @@ +package hastabel; + +import java.util.Collection; +import java.util.Map; +import java.util.HashMap; + +public class Elements +{ + private final boolean is_root_mgr; + + private final Map from_name; + + public Elements (final boolean is_root_mgr) + { + from_name = new HashMap(); + this.is_root_mgr = is_root_mgr; + } + + public Element declare (final Type type, final String name) + { + final Element result, previous_instance; + + result = new Element(type, name); + + previous_instance = from_name.get(name); + + if (previous_instance == null) + { + from_name.put(name, result); + + if (is_root_mgr) + { + type.add_element(result); + } + + return result; + } + + if (type.equals(previous_instance.get_type())) + { + return previous_instance; + } + + if (previous_instance.get_type().includes(type)) + { + System.err.println + ( + "[W] Element \"" + + name + + "\" was declared as a \"" + + previous_instance.get_type().get_name() + + "\", but is now declared as its \"" + + type.get_name() + + "\" sub-type. \"" + + type.get_name() + + "\" declaration ignored." + ); + + return previous_instance; + } + + System.err.println + ( + "[E] Conflicting types for element \"" + + name + + "\": was \"" + + previous_instance.get_type().get_name() + + "\", is now \"" + + type.get_name() + + "\"." + ); + + return null; + } + + public Element get (final String name) + { + final Element result; + + result = from_name.get(name); + + if (result == null) + { + System.err.println("[F] Undeclared element \"" + name + "\"."); + + System.exit(-1); + + return null; + } + + return result; + } + + public Collection get_all () + { + return from_name.values(); + } +} diff --git a/src/hastabel/LangLexer.g4 b/src/hastabel/LangLexer.g4 new file mode 100644 index 0000000..45062f0 --- /dev/null +++ b/src/hastabel/LangLexer.g4 @@ -0,0 +1,25 @@ +lexer grammar LangLexer; + +@header {package hastabel;} + +fragment SEP: [ \t\r\n]+; + +L_PAREN: '('; +R_PAREN: ')'; +L_BRAKT: '{'; +R_BRAKT: '}'; +COMMA: ','; +SUB_TYPE_OF: '::'; +STAR: '*'; + +ADD_TYPE_KW: 'add_type' SEP; +ADD_RELATION_KW: 'add_relation' SEP; +ADD_TEMPLATE_KW: 'add_template' SEP; + +WS: SEP; + +ID: [a-zA-Z0-9_.]+; + +STRING: '"' ~('\r' | '\n' | '"')* '"'; + +COMMENT: (';;'|'#'|'//'|'%') .*? '\n' -> channel(HIDDEN); diff --git a/src/hastabel/LangParser.g4 b/src/hastabel/LangParser.g4 new file mode 100644 index 0000000..0333bc1 --- /dev/null +++ b/src/hastabel/LangParser.g4 @@ -0,0 +1,279 @@ +parser grammar LangParser; + +options +{ + tokenVocab = LangLexer; +} + +@header +{ + package hastabel; + + import hastabel.lang.Predicate; + import hastabel.lang.Element; +} + +@members +{ + World WORLD; + /* of the class */ +} + +lang_file [World init_world]: + @init + { + WORLD = init_world; + } + + (lang_instr)* + { + } +; + +lang_instr: + (WS)* ADD_TYPE_KW (WS)* new_type (WS)* + { + } + + | (WS)* ADD_RELATION_KW (WS)* new_predicate (WS)* + { + } + + | (WS)* ADD_TEMPLATE_KW (WS)* new_template (WS)* + { + } + + | (WS)* ID (WS)* L_PAREN (WS)* ident_list (WS*) R_PAREN (WS)* + { + final Predicate predicate; + final List params; + final Iterator param_names; + + predicate = WORLD.get_predicates_manager().get(($ID.text)); + + if (predicate == null) + { + WORLD.invalidate(); + } + else + { + params = new ArrayList(); + + param_names = ($ident_list.list).iterator(); + + while (param_names.hasNext()) + { + params.add(WORLD.get_elements_manager().get(param_names.next())); + } + + predicate.add_member(params); + } + } + + | (WS)* ID (WS)+ ident_list (WS)* + { + final Type type; + final Iterator elem_names; + + type = WORLD.get_types_manager().get(($ID.text)); + + if (type == null) + { + WORLD.invalidate(); + } + else + { + elem_names = ($ident_list.list).iterator(); + + while (elem_names.hasNext()) + { + WORLD.get_elements_manager().declare(type, elem_names.next()); + } + } + } + + | (WS)* STAR (WS)* ID (WS)+ ident_list (WS)* + { + final Template subtemplate; + final Iterator elem_names; + + subtemplate = WORLD.get_templates_manager().get(($ID.text)); + + if (subtemplate == null) + { + WORLD.invalidate(); + } + else + { + elem_names = ($ident_list.list).iterator(); + + while (elem_names.hasNext()) + { + final TemplateInstance ti; + + ti = + WORLD.get_template_instances_manager().declare + ( + subtemplate, + elem_names.next() + ); + + ti.add_contents_to + ( + WORLD.get_elements_manager(), + WORLD.get_predicates_manager() + ); + } + } + } +; + +new_type: + parent=ID (WS)* SUB_TYPE_OF (WS)* type=ID + { + final Type parent_type; + + parent_type = WORLD.get_types_manager().get(($parent.text)); + + WORLD.get_types_manager().declare(parent_type, ($type.text)); + } + + | ID + { + WORLD.get_types_manager().declare(null, ($ID.text)); + } +; + +new_predicate: + ID (WS)* L_PAREN (WS)* ident_list (WS)* R_PAREN + { + final List signature; + final Iterator type_names; + + signature = new ArrayList(); + + type_names = ($ident_list.list).iterator(); + + while (type_names.hasNext()) + { + signature.add(WORLD.get_types_manager().get(type_names.next())); + } + + WORLD.get_predicates_manager().declare(signature, ($ID.text)); + } +; + +new_template + @init + { + Template template; + }: + + ID { template = WORLD.get_templates_manager().declare(($ID.text)); } + (WS)* L_BRAKT (WS)* (template_instr[template])* (WS)* R_BRAKT + { + } +; + +template_instr [Template template]: + (WS)* ID (WS)* L_PAREN (WS)* ident_list (WS*) R_PAREN (WS)* + { + final Predicate predicate; + final List params; + final Iterator param_names; + + predicate = + template.get_predicates_manager().get_or_duplicate(($ID.text)); + + if (predicate == null) + { + WORLD.invalidate(); + } + else + { + params = new ArrayList(); + + param_names = ($ident_list.list).iterator(); + + while (param_names.hasNext()) + { + params.add(template.get_elements_manager().get(param_names.next())); + } + + predicate.add_member(params); + } + } + + | (WS)* ID (WS)+ ident_list (WS)* + { + final Type type; + final Iterator elem_names; + + type = WORLD.get_types_manager().get(($ID.text)); + + if (type == null) + { + WORLD.invalidate(); + } + else + { + elem_names = ($ident_list.list).iterator(); + + while (elem_names.hasNext()) + { + template.get_elements_manager().declare(type, elem_names.next()); + } + } + } + + | (WS)* STAR (WS)* ID (WS)+ ident_list (WS)* + { + final Template subtemplate; + final Iterator elem_names; + + subtemplate = WORLD.get_templates_manager().get(($ID.text)); + + if (subtemplate == null) + { + WORLD.invalidate(); + } + else + { + elem_names = ($ident_list.list).iterator(); + + while (elem_names.hasNext()) + { + final TemplateInstance ti; + + ti = template.get_template_instances_manager.declare + ( + subtemplate, + elem_names.next() + ); + + ti.add_contents_to(template); + } + } + } +; + +ident_list returns [List list] + @init + { + final List result = new ArrayList(); + } + + : + first_element=ID + ( + (WS)* COMMA (WS)* next_element=ID + { + result.add(($next_element.text).replaceAll("\\.", "__")); + } + )* + { + result.add(0, ($first_element.text).replaceAll("\\.", "__")); + + $list = result; + } +; diff --git a/src/hastabel/LogicWorld.java b/src/hastabel/LogicWorld.java new file mode 100644 index 0000000..c14331a --- /dev/null +++ b/src/hastabel/LogicWorld.java @@ -0,0 +1,34 @@ +package hastabel; + +import java.io.IOException; + +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; + +class LogicWorld +{ + protected final Elements elements_mgr; + protected final Predicates predicates_mgr; + + public LogicWorld () + { + elements_mgr = new Elements(); + predicates_mgr = new Predicates(null); + } + + public LogicWorld (final LogicWorld parent) + { + elements_mgr = new Elements(); + predicates_mgr = new Predicates(parent.get_predicates_manager()); + } + + public Elements get_elements_manager () + { + return elements_mgr; + } + + public Predicates get_predicates_manager () + { + return predicates_mgr; + } +} diff --git a/src/hastabel/Predicates.java b/src/hastabel/Predicates.java new file mode 100644 index 0000000..07c47a3 --- /dev/null +++ b/src/hastabel/Predicates.java @@ -0,0 +1,101 @@ +package hastabel; + +import hastabel.lang.Predicate; +import hastabel.lang.Type; + +import java.util.Collection; +import java.util.Map; +import java.util.Iterator; +import java.util.Set; +import java.util.List; +import java.util.HashMap; +import java.util.HashSet; +import java.util.ArrayList; + +public class Predicates +{ + private final Map from_name; + private final Predicates parent_mgr; + + public Predicates (final Predicates parent_mgr) + { + from_name = new HashMap(); + this.parent_mgr = parent_mgr; + } + + public Predicate declare (final List signature, final String name) + { + final Predicate result, previous_instance; + + result = new Predicate(signature, name); + + previous_instance = from_name.get(name); + + if (previous_instance == null) + { + from_name.put(name, result); + + return result; + } + + if (signature.equals(previous_instance.get_signature())) + { + return previous_instance; + } + + System.err.println + ( + "[F] Conflicting signatures for predicate \"" + + name + + "\"." + ); + + return null; + } + + public Predicate get_or_duplicate (final String name) + { + Predicate result; + + result = from_name.get(name); + + if (result == null) + { + final Predicate main_predicate; + + main_predicate = parent_mgr.get(name); + + if (main_predicate == null) + { + return null; + } + + result = main_predicate.shallow_copy(); + + from_name.put(name, result); + } + + return result; + } + + public Predicate get (final String name) + { + final Predicate result; + + result = from_name.get(name); + + if (result == null) + { + System.err.println("[E] Undeclared predicate \"" + name + "\"."); + + return null; + } + + return result; + } + + public Collection get_all () + { + return from_name.values(); + } +} diff --git a/src/hastabel/Template.java b/src/hastabel/Template.java new file mode 100644 index 0000000..d1077d3 --- /dev/null +++ b/src/hastabel/Template.java @@ -0,0 +1,105 @@ +package hastabel; + +import hastabel.lang.Element; +import hastabel.lang.Predicate; + +import java.util.List; +import java.util.Collection; +import java.util.ArrayList; + +public class Template extends LogicWorld +{ + private final static String INSTANCE_SEP = "__"; + + private final TemplateInstances template_instances; + private final String name; + + public Template (final LogicWorld parent, final String name) + { + super(parent); + + template_instances = new TemplateInstances(); + + this.name = name; + } + + public String get_name () + { + return name; + } + + public TemplateInstances get_template_instances_manager () + { + return template_instances; + } + + public void add_contents_to (final String prefix, final Template t) + { + add_contents_to(prefix, t.elements, t.predicates); + } + + public void add_contents_to + ( + final String prefix, + final Elements dest_elements, + final Predicates dest_predicates + ) + { + final String actual_prefix; + + actual_prefix = prefix + INSTANCE_SEP; + + for (final Element e: elements_mgr.get_all()) + { + dest_elements.declare(e.get_type(), (actual_prefix + e.get_name())); + } + + for (final Predicate orig_rel: predicates_mgr.get_all()) + { + final Predicate dest_rel; + + dest_rel = dest_predicates.get_or_duplicate(orig_rel.get_name()); + + for (final List orig_membs: orig_rel.get_members()) + { + final List dest_membs; + + dest_membs = new ArrayList(orig_membs.size()); + + for (final Element e: orig_membs) + { + dest_membs.add(dest_elements.get(actual_prefix + e.get_name())); + } + + dest_rel.add_member(dest_membs); + } + } + } + + @Override + public boolean equals (Object o) + { + final Template t; + + if ((o == null) || !(o instanceof Template)) + { + return false; + } + + t = (Template) o; + + return (t.name.equals(name)); + } + + @Override + public int hashCode () + { + return name.hashCode(); + } + + @Override + public String toString () + { + return "Template " + name; + } +} diff --git a/src/hastabel/TemplateInstance.java b/src/hastabel/TemplateInstance.java new file mode 100644 index 0000000..16fa2a1 --- /dev/null +++ b/src/hastabel/TemplateInstance.java @@ -0,0 +1,37 @@ +package hastabel; + +public class TemplateInstance +{ + private final Template template; + private final String name; + + public TemplateInstance + ( + final Template template, + final String name + ) + { + this.template = template; + this.name = name; + } + + public String get_name () + { + return name; + } + + public Template get_template () + { + return template; + } + + public void add_contents_to (final Template t) + { + template.add_contents_to(name, t); + } + + public void add_contents_to (final Elements e, final Predicates r) + { + template.add_contents_to(name, e, r); + } +} diff --git a/src/hastabel/TemplateInstances.java b/src/hastabel/TemplateInstances.java new file mode 100644 index 0000000..35bba7f --- /dev/null +++ b/src/hastabel/TemplateInstances.java @@ -0,0 +1,61 @@ +package hastabel; + +import java.util.Collection; +import java.util.Map; +import java.util.HashMap; + +public class TemplateInstances +{ + private final Map from_name; + + public TemplateInstances () + { + from_name = new HashMap(); + } + + public TemplateInstance declare (final Template template, final String name) + { + final TemplateInstance result, previous_instance; + + result = new TemplateInstance(template, name); + + previous_instance = from_name.get(name); + + if (previous_instance == null) + { + from_name.put(name, result); + + return result; + } + + System.err.println + ( + "[E] Multiple declarations for template instance \"" + + name + + "\"." + ); + + return null; + } + + public TemplateInstance get (final String name) + { + final TemplateInstance result; + + result = from_name.get(name); + + if (result == null) + { + System.err.println("[F] Undeclared template \"" + name + "\"."); + + return null; + } + + return result; + } + + public Collection get_all () + { + return from_name.values(); + } +} diff --git a/src/hastabel/Templates.java b/src/hastabel/Templates.java new file mode 100644 index 0000000..287906f --- /dev/null +++ b/src/hastabel/Templates.java @@ -0,0 +1,63 @@ +package hastabel; + +import java.util.Collection; +import java.util.Map; +import java.util.HashMap; + +public class Templates +{ + private final Map from_name; + + public Templates () + { + from_name = new HashMap(); + } + + public Template declare (final LogicWorld parent, final String name) + { + final Template previous_instance; + + previous_instance = from_name.get(name); + + if (previous_instance == null) + { + final Template result; + + result = new Template(parent, name); + + from_name.put(name, result); + + return result; + } + + System.err.println + ( + "[E] Multiple declarations for template \"" + + name + + "\"." + ); + + return null; + } + + public Template get (final String name) + { + final Template result; + + result = from_name.get(name); + + if (result == null) + { + System.err.println("[E] Undeclared template \"" + name + "\"."); + + return null; + } + + return result; + } + + public Collection