Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Improve type system to support anonymous functions #136

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
64 changes: 31 additions & 33 deletions core/src/main/antlr4/Metapath10.g4
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ options { tokenVocab=Metapath10Lexer; superClass=Metapath10ParserBase; }

// [1]
metapath : expr EOF ;
// paramlist : param ( COMMA param)* ;
// param : DOLLAR eqname typedeclaration? ;
// functionbody : enclosedexpr ;
paramlist : param ( COMMA param)* ;
param : DOLLAR eqname typedeclaration? ;
functionbody : enclosedexpr ;
// [5]
enclosedexpr : OC expr? CC ;
expr : exprsingle ( COMMA exprsingle)* ;
Expand All @@ -33,13 +33,12 @@ rangeexpr : additiveexpr ( KW_TO additiveexpr )? ;
additiveexpr : multiplicativeexpr ( (PLUS | MINUS) multiplicativeexpr )* ;
multiplicativeexpr : unionexpr ( (STAR | KW_DIV | KW_IDIV | KW_MOD) unionexpr )* ;
unionexpr : intersectexceptexpr ( (KW_UNION | P) intersectexceptexpr )* ;
// intersectexceptexpr : instanceofexpr ( ( KW_INTERSECT | KW_EXCEPT) instanceofexpr )* ;
intersectexceptexpr : arrowexpr ( ( KW_INTERSECT | KW_EXCEPT) arrowexpr )* ;
intersectexceptexpr : instanceofexpr ( ( KW_INTERSECT | KW_EXCEPT) instanceofexpr )* ;
// [25]
// instanceofexpr : treatexpr ( KW_INSTANCE KW_OF sequencetype )? ;
// treatexpr : castableexpr ( KW_TREAT KW_AS sequencetype )? ;
// castableexpr : castexpr ( KW_CASTABLE KW_AS singletype )? ;
// castexpr : arrowexpr ( KW_CAST KW_AS singletype )? ;
instanceofexpr : treatexpr ( KW_INSTANCE KW_OF sequencetype )? ;
treatexpr : castableexpr ( KW_TREAT KW_AS sequencetype )? ;
castableexpr : castexpr ( KW_CASTABLE KW_AS singletype )? ;
castexpr : arrowexpr ( KW_CAST KW_AS singletype )? ;
arrowexpr : unaryexpr ( EG arrowfunctionspecifier argumentlist )* ;
// [30]
unaryexpr : ( MINUS | PLUS)* valueexpr ;
Expand Down Expand Up @@ -74,10 +73,8 @@ predicate : OB expr CB ;
lookup : QM keyspecifier ;
keyspecifier : NCName | IntegerLiteral | parenthesizedexpr | STAR ;
// [55]
//arrowfunctionspecifier : eqname | varref | parenthesizedexpr ;
arrowfunctionspecifier : eqname;
// primaryexpr : literal | varref | parenthesizedexpr | contextitemexpr | functioncall | functionitemexpr | mapconstructor | arrayconstructor | unarylookup ;
primaryexpr : literal | varref | parenthesizedexpr | contextitemexpr | functioncall | mapconstructor | arrayconstructor | unarylookup;
arrowfunctionspecifier : eqname | varref | parenthesizedexpr ;
primaryexpr : literal | varref | parenthesizedexpr | contextitemexpr | functioncall | functionitemexpr | mapconstructor | arrayconstructor | unarylookup ;
literal : numericliteral | StringLiteral ;
numericliteral : IntegerLiteral | DecimalLiteral | DoubleLiteral ;
varref : DOLLAR varname ;
Expand All @@ -90,9 +87,9 @@ functioncall : { this.isFuncCall() }? eqname argumentlist ;
argument : exprsingle ;
// [65]
// argumentplaceholder : QM ;
// functionitemexpr : namedfunctionref | inlinefunctionexpr ;
// namedfunctionref : eqname POUND IntegerLiteral /* xgc: reserved-function-names */;
// inlinefunctionexpr : KW_FUNCTION OP paramlist? CP ( KW_AS sequencetype)? functionbody ;
functionitemexpr : namedfunctionref | inlinefunctionexpr ;
namedfunctionref : eqname POUND IntegerLiteral /* xgc: reserved-function-names */;
inlinefunctionexpr : KW_FUNCTION OP paramlist? CP ( KW_AS sequencetype)? functionbody ;
mapconstructor : KW_MAP OC (mapconstructorentry ( COMMA mapconstructorentry)*)? CC ;
// [70]
mapconstructorentry : mapkeyexpr COLON mapvalueexpr ;
Expand All @@ -103,13 +100,14 @@ squarearrayconstructor : OB (exprsingle ( COMMA exprsingle)*)? CB ;
// [75]
curlyarrayconstructor : KW_ARRAY enclosedexpr ;
unarylookup : QM keyspecifier ;
// singletype : simpletypename QM? ;
// typedeclaration : KW_AS sequencetype ;
// sequencetype : KW_EMPTY_SEQUENCE OP CP | itemtype occurrenceindicator? ;
singletype : simpletypename QM? ;
typedeclaration : KW_AS sequencetype ;
sequencetype : KW_EMPTY_SEQUENCE OP CP | itemtype occurrenceindicator? ;
// [80]
// occurrenceindicator : QM | STAR | PLUS ;
occurrenceindicator : QM | STAR | PLUS ;
itemtype : KW_ITEM OP CP | functiontest | maptest | arraytest | atomicoruniontype | parenthesizeditemtype ;
// itemtype : kindtest | KW_ITEM OP CP | functiontest | maptest | arraytest | atomicoruniontype | parenthesizeditemtype ;
// atomicoruniontype : eqname ;
atomicoruniontype : eqname ;
// kindtest : documenttest | elementtest | attributetest | schemaelementtest | schemaattributetest | pitest | commenttest | texttest | namespacenodetest | anykindtest ;
// anykindtest : KW_NODE OP CP ;
// [85]
Expand All @@ -131,20 +129,20 @@ unarylookup : QM keyspecifier ;
// attributename : eqname ;
// elementname : eqname ;
// [100]
// simpletypename : typename_ ;
// typename_ : eqname ;
// functiontest : anyfunctiontest | typedfunctiontest ;
// anyfunctiontest : KW_FUNCTION OP STAR CP ;
// typedfunctiontest : KW_FUNCTION OP (sequencetype ( COMMA sequencetype)*)? CP KW_AS sequencetype ;
simpletypename : typename_ ;
typename_ : eqname ;
functiontest : anyfunctiontest | typedfunctiontest ;
anyfunctiontest : KW_FUNCTION OP STAR CP ;
typedfunctiontest : KW_FUNCTION OP (sequencetype ( COMMA sequencetype)*)? CP KW_AS sequencetype ;
// [105]
// maptest : anymaptest | typedmaptest ;
// anymaptest : KW_MAP OP STAR CP ;
// typedmaptest : KW_MAP OP atomicoruniontype COMMA sequencetype CP ;
// arraytest : anyarraytest | typedarraytest ;
// anyarraytest : KW_ARRAY OP STAR CP ;
maptest : anymaptest | typedmaptest ;
anymaptest : KW_MAP OP STAR CP ;
typedmaptest : KW_MAP OP atomicoruniontype COMMA sequencetype CP ;
arraytest : anyarraytest | typedarraytest ;
anyarraytest : KW_ARRAY OP STAR CP ;
// [110]
// typedarraytest : KW_ARRAY OP sequencetype CP ;
// parenthesizeditemtype : OP itemtype CP ;
typedarraytest : KW_ARRAY OP sequencetype CP ;
parenthesizeditemtype : OP itemtype CP ;


// Error in the spec. EQName also includes acceptable keywords.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@ public abstract class AbstractCustomJavaDataTypeAdapter<
* Construct a new Java type adapter for the class based on
* {@link ICustomJavaDataType}.
*
* @param clazz
* @param valueClass
* a data type class based on {@link ICustomJavaDataType}
* @param itemClass
* the Java type of the Matepath item this adapter supports
*/
public AbstractCustomJavaDataTypeAdapter(@NonNull Class<TYPE> clazz) {
super(clazz);
public AbstractCustomJavaDataTypeAdapter(
@NonNull Class<TYPE> valueClass,
@NonNull Class<ITEM_TYPE> itemClass) {
super(valueClass, itemClass);
}

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
import com.fasterxml.jackson.core.JsonParser;

import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
import gov.nist.secauto.metaschema.core.metapath.type.IAtomicOrUnionType;
import gov.nist.secauto.metaschema.core.metapath.type.impl.DataTypeItemType;
import gov.nist.secauto.metaschema.core.model.util.JsonUtil;
import gov.nist.secauto.metaschema.core.model.util.XmlEventUtil;
import gov.nist.secauto.metaschema.core.qname.IEnhancedQName;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;

import org.codehaus.stax2.XMLEventReader2;
Expand All @@ -20,7 +23,6 @@
import java.io.IOException;
import java.net.URI;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
Expand All @@ -47,16 +49,23 @@ public abstract class AbstractDataTypeAdapter<TYPE, ITEM_TYPE extends IAnyAtomic
public static final String DEFAULT_JSON_FIELD_VALUE_NAME = "STRVALUE";

@NonNull
private final Class<TYPE> clazz;
private final Class<TYPE> valueClass;
@NonNull
private final IAtomicOrUnionType itemType;

/**
* Construct a new Java type adapter for a provided class.
*
* @param clazz
* the Java type this adapter supports
* @param valueClass
* the Java value object type this adapter supports
* @param itemClass
* the Java type of the Matepath item this adapter supports
*/
protected AbstractDataTypeAdapter(@NonNull Class<TYPE> clazz) {
this.clazz = clazz;
protected AbstractDataTypeAdapter(
@NonNull Class<TYPE> valueClass,
@NonNull Class<ITEM_TYPE> itemClass) {
this.valueClass = valueClass;
this.itemType = new DataTypeItemType(this, itemClass);
}

@Override
Expand All @@ -67,11 +76,16 @@ public TYPE toValue(Object value) {

@Override
public Class<TYPE> getJavaClass() {
return clazz;
return valueClass;
}

@Override
public IAtomicOrUnionType getItemType() {
return itemType;
}

@Override
public boolean canHandleQName(QName nextQName) {
public boolean canHandleQName(IEnhancedQName nextQName) {
return false;
}

Expand Down Expand Up @@ -172,7 +186,7 @@ public void writeXmlValue(
}

@Override
public void writeXmlValue(Object value, QName parentName, XMLStreamWriter2 writer) throws IOException {
public void writeXmlValue(Object value, IEnhancedQName parentName, XMLStreamWriter2 writer) throws IOException {
String content;
try {
content = asString(value);
Expand All @@ -191,9 +205,6 @@ public void writeJsonValue(Object value, JsonGenerator generator) throws IOExcep
}
}

@Override
public abstract Class<ITEM_TYPE> getItemClass();

@Override
public abstract ITEM_TYPE newItem(Object value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@

package gov.nist.secauto.metaschema.core.datatype;

import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
import gov.nist.secauto.metaschema.core.qname.IEnhancedQName;
import gov.nist.secauto.metaschema.core.qname.QNameCache;
import gov.nist.secauto.metaschema.core.util.CustomCollectors;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand All @@ -15,7 +19,6 @@
import java.util.ServiceLoader;
import java.util.ServiceLoader.Provider;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.xml.namespace.QName;
Expand All @@ -30,11 +33,11 @@
*/
public final class DataTypeService {
private static final Logger LOGGER = LogManager.getLogger(DataTypeService.class);
private static final Lazy<DataTypeService> INSTANCE = Lazy.lazy(() -> new DataTypeService());
private static final Lazy<DataTypeService> INSTANCE = Lazy.lazy(DataTypeService::new);

private final Map<String, IDataTypeAdapter<?>> typeByName;
private final Map<QName, IDataTypeAdapter<?>> typeByQName;
private final Map<Class<? extends IDataTypeAdapter<?>>, IDataTypeAdapter<?>> typeByClass;
private final Map<Integer, IDataTypeAdapter<?>> typeByQNameIndex;
private final Map<Class<? extends IDataTypeAdapter<?>>, IDataTypeAdapter<?>> typeByAdapterClass;
private final Map<Class<? extends IAnyAtomicItem>, IDataTypeAdapter<?>> typeByItemClass;

/**
* Get the singleton service instance, which will be lazy constructed on first
Expand All @@ -44,21 +47,20 @@ public final class DataTypeService {
*/
@SuppressWarnings("null")
@NonNull
public static DataTypeService getInstance() {
public static DataTypeService instance() {
return INSTANCE.get();
}

private DataTypeService() {

ServiceLoader<IDataTypeProvider> loader = ServiceLoader.load(IDataTypeProvider.class);
List<IDataTypeAdapter<?>> dataTypes = loader.stream()
.map(Provider<IDataTypeProvider>::get)
.flatMap(provider -> provider.getJavaTypeAdapters().stream())
.collect(Collectors.toList());

Map<String, IDataTypeAdapter<?>> typeByName = dataTypes.stream()
this.typeByQNameIndex = dataTypes.stream()
.flatMap(dataType -> dataType.getNames().stream()
.map(qname -> Map.entry(qname.getLocalPart(), dataType)))
.map(qname -> Map.entry(qname.getIndexPosition(), dataType)))
.collect(CustomCollectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
Expand All @@ -73,44 +75,37 @@ private DataTypeService() {
},
ConcurrentHashMap::new));

Map<QName, IDataTypeAdapter<?>> typeByQName = dataTypes.stream()
.flatMap(dataType -> dataType.getNames().stream()
.map(qname -> Map.entry(qname, dataType)))
this.typeByAdapterClass = dataTypes.stream()
.collect(CustomCollectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
dataType -> ObjectUtils.asNullableType(dataType.getClass()),
CustomCollectors.identity(),
(key, v1, v2) -> {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("Data types '{}' and '{}' have duplicate name '{}'. Using the first.",
v1.getClass().getName(),
v2.getClass().getName(),
key);
LOGGER.warn("Duplicate data type class '{}'. Using the first.",
key.getClass().getName());
}
return v1;
},
ConcurrentHashMap::new));

@SuppressWarnings({ "unchecked", "null" })
Map<Class<? extends IDataTypeAdapter<?>>,
IDataTypeAdapter<?>> typeByClass = dataTypes.stream()
.collect(CustomCollectors.toMap(
dataType -> (Class<? extends IDataTypeAdapter<?>>) dataType.getClass(),
Function.identity(),
(key, v1, v2) -> {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("Duplicate data type class '{}'. Using the first.",
key.getClass().getName());
}
return v1;
},
ConcurrentHashMap::new));
this.typeByName = typeByName;
this.typeByQName = typeByQName;
this.typeByClass = typeByClass;
this.typeByItemClass = dataTypes.stream()
.collect(CustomCollectors.toMap(
dataType -> ObjectUtils.asNullableType(dataType.getItemType().getItemClass()),
CustomCollectors.identity(),
(key, v1, v2) -> {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("Duplicate item class '{}' declared by adapters '{}' and '{}'. Using the first.",
key.getName(),
v1.getClass().getName(),
v2.getClass().getName());
}
return v1;
},
ConcurrentHashMap::new));
}

/**
* Lookup a specific {@link IDataTypeAdapter} instance by its name.
* Lookup a specific {@link IDataTypeAdapter} instance by its QName.
*
* @param qname
* the qualified name of data type adapter to get the instance for
Expand All @@ -119,20 +114,23 @@ private DataTypeService() {
*/
@Nullable
public IDataTypeAdapter<?> getJavaTypeAdapterByQName(@NonNull QName qname) {
return typeByQName.get(qname);
IEnhancedQName result = QNameCache.instance().get(qname);
return result == null ? null : getJavaTypeAdapterByQNameIndex(result.getIndexPosition());
}

/**
* Lookup a specific {@link IDataTypeAdapter} instance by its name.
* Lookup a specific {@link IDataTypeAdapter} instance by its QName index
* position.
*
* @param name
* the name of data type adapter to get the instance for
* @param qnameIndexPosition
* the position in the global QName index for the qualified name of
* data type adapter to get the instance for
* @return the instance or {@code null} if the instance is unknown to the type
* system
*/
@Nullable
public IDataTypeAdapter<?> getJavaTypeAdapterByName(@NonNull String name) {
return typeByName.get(name);
public IDataTypeAdapter<?> getJavaTypeAdapterByQNameIndex(int qnameIndexPosition) {
return typeByQNameIndex.get(qnameIndexPosition);
}

/**
Expand All @@ -148,6 +146,11 @@ public IDataTypeAdapter<?> getJavaTypeAdapterByName(@NonNull String name) {
@SuppressWarnings("unchecked")
@Nullable
public <TYPE extends IDataTypeAdapter<?>> TYPE getJavaTypeAdapterByClass(@NonNull Class<TYPE> clazz) {
return (TYPE) typeByClass.get(clazz);
return (TYPE) typeByAdapterClass.get(clazz);
}

@Nullable
public IDataTypeAdapter<?> getJavaTypeAdapterByItemClass(Class<? extends IAnyAtomicItem> clazz) {
return typeByItemClass.get(clazz);
}
}
Loading
Loading