/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * SourceModelBuilder.java * Created: Nov 19, 2004 * By: Bo Ilic */ package org.openquark.cal.compiler; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import org.openquark.cal.compiler.SourceModel.CALDoc.TextSegment.TopLevel; import org.openquark.cal.compiler.SourceModel.Import.UsingItem; import org.openquark.cal.compiler.SourceModel.Name.DataCons; /** * Builds an appropriate SourceModel from a ParseTreeNode. The ParseTreeNode is assumed to be of * the form defined by the antlr file CALTreeParser.g (the tree grammar for CAL). * * @author Bo Ilic */ final class SourceModelBuilder { static SourceModel.ModuleDefn buildModuleDefn(ParseTreeNode moduleDefnNode) { moduleDefnNode.verifyType(CALTreeParserTokenTypes.MODULE_DEFN); ParseTreeNode optionalCALDocNode = moduleDefnNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.Module caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.Module.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode moduleNameNode = optionalCALDocNode.nextSibling(); SourceModel.Name.Module moduleName = buildModuleName(moduleNameNode); ParseTreeNode importDeclarationListNode = moduleNameNode.nextSibling(); importDeclarationListNode.verifyType(CALTreeParserTokenTypes.IMPORT_DECLARATION_LIST); int numberOfImports = importDeclarationListNode.getNumberOfChildren(); SourceModel.Import[] importedModules = new SourceModel.Import[numberOfImports]; ParseTreeNode importDeclarationNode = importDeclarationListNode.firstChild(); for (int i = 0; i < numberOfImports; i++) { importedModules[i] = buildImport(importDeclarationNode); importDeclarationNode = importDeclarationNode.nextSibling(); } ParseTreeNode friendDeclarationListNode = importDeclarationListNode.nextSibling(); friendDeclarationListNode.verifyType(CALTreeParserTokenTypes.FRIEND_DECLARATION_LIST); int numberOfFriends = friendDeclarationListNode.getNumberOfChildren(); SourceModel.Friend[] friendModules = new SourceModel.Friend[numberOfFriends]; ParseTreeNode friendDeclarationNode = friendDeclarationListNode.firstChild(); for (int i = 0; i < numberOfFriends; i++) { friendModules[i] = buildFriend(friendDeclarationNode); friendDeclarationNode = friendDeclarationNode.nextSibling(); } ParseTreeNode outerDefnListNode = friendDeclarationListNode.nextSibling(); outerDefnListNode.verifyType(CALTreeParserTokenTypes.OUTER_DEFN_LIST); int numberOfOuterDefns = outerDefnListNode.getNumberOfChildren(); SourceModel.TopLevelSourceElement[] topLevelDefns = new SourceModel.TopLevelSourceElement[numberOfOuterDefns]; int i = 0; for (final ParseTreeNode outerDefnNode : outerDefnListNode) { switch (outerDefnNode.getType()) { case CALTreeParserTokenTypes.TOP_LEVEL_TYPE_DECLARATION : { topLevelDefns[i] = buildFunctionTypeDeclaration(outerDefnNode); break; } case CALTreeParserTokenTypes.TOP_LEVEL_FUNCTION_DEFN : { topLevelDefns[i] = buildAlgebraicFunctionDefn(outerDefnNode); break; } case CALTreeParserTokenTypes.FOREIGN_FUNCTION_DECLARATION : { topLevelDefns[i] = buildForeignFunctionDefn(outerDefnNode); break; } case CALTreeParserTokenTypes.PRIMITIVE_FUNCTION_DECLARATION: { topLevelDefns[i] = buildPrimitiveFunctionDefn(outerDefnNode); break; } case CALTreeParserTokenTypes.DATA_DECLARATION : { topLevelDefns[i] = buildAlgebraicTypeDefn(outerDefnNode); break; } case CALTreeParserTokenTypes.FOREIGN_DATA_DECLARATION : { topLevelDefns[i] = buildForeignTypeDefn(outerDefnNode); break; } case CALTreeParserTokenTypes.TYPE_CLASS_DEFN : { topLevelDefns[i] = buildTypeClassDefn(outerDefnNode); break; } case CALTreeParserTokenTypes.INSTANCE_DEFN : { topLevelDefns[i] = buildInstanceDefn(outerDefnNode); break; } default : { throw new IllegalStateException("Unexpected parse tree node " + outerDefnNode.toDebugString() + "."); } } ++i; } return SourceModel.ModuleDefn.makeAnnotated(caldocComment, moduleName, importedModules, friendModules, topLevelDefns, moduleName.getSourceRange()); } static SourceModel.Import.UsingItem buildImportUsingItem(ParseTreeNode usingItemNode) { int nodeType = usingItemNode.getType(); int nameType = (nodeType == CALTreeParserTokenTypes.LITERAL_function) ? CALTreeParserTokenTypes.VAR_ID : CALTreeParserTokenTypes.CONS_ID; List<String> usingNames = new ArrayList<String>(); List<SourceRange> usingNameSourceRanges = new ArrayList<SourceRange>(); for (final ParseTreeNode nameNode : usingItemNode) { nameNode.verifyType(nameType); usingNames.add(nameNode.getText()); usingNameSourceRanges.add(nameNode.getAssemblySourceRange()); } final String[] emptyStrings = new String[0]; final SourceRange[] emptySourceRanges = new SourceRange[0]; switch(nodeType) { case CALTreeParserTokenTypes.LITERAL_function: return SourceModel.Import.UsingItem.Function.makeAnnotated( usingNames.toArray(emptyStrings), usingItemNode.getAssemblySourceRange(), usingNameSourceRanges.toArray(emptySourceRanges)); case CALTreeParserTokenTypes.LITERAL_dataConstructor: return SourceModel.Import.UsingItem.DataConstructor.makeAnnotated( usingNames.toArray(emptyStrings), usingItemNode.getAssemblySourceRange(), usingNameSourceRanges.toArray(emptySourceRanges)); case CALTreeParserTokenTypes.LITERAL_typeConstructor: return SourceModel.Import.UsingItem.TypeConstructor.makeAnnotated( usingNames.toArray(emptyStrings), usingItemNode.getAssemblySourceRange(), usingNameSourceRanges.toArray(emptySourceRanges)); case CALTreeParserTokenTypes.LITERAL_typeClass: return SourceModel.Import.UsingItem.TypeClass.makeAnnotated( usingNames.toArray(emptyStrings), usingItemNode.getAssemblySourceRange(), usingNameSourceRanges.toArray(emptySourceRanges)); default: throw new IllegalStateException("Unexpected parse tree node " + usingItemNode.toDebugString() + "."); } } static SourceModel.Import buildImport(ParseTreeNode importDeclarationNode) { importDeclarationNode.verifyType(CALTreeParserTokenTypes.LITERAL_import); ParseTreeNode importedModuleNameNode = importDeclarationNode.firstChild(); SourceModel.Name.Module importedModuleName = buildModuleName(importedModuleNameNode); List<UsingItem> usingItems = new ArrayList<UsingItem>(); ParseTreeNode usingClauseNode = importedModuleNameNode.nextSibling(); if (usingClauseNode != null) { usingClauseNode.verifyType(CALTreeParserTokenTypes.LITERAL_using); for (final ParseTreeNode usingItemNode : usingClauseNode) { usingItems.add(buildImportUsingItem(usingItemNode)); } } final SourceModel.Import.UsingItem[] emptyUsingItems = new SourceModel.Import.UsingItem[0]; SourceModel.Import importStatement = SourceModel.Import.makeAnnotated(importedModuleName, usingItems.toArray(emptyUsingItems), importDeclarationNode.getAssemblySourceRange()); return importStatement; } static SourceModel.Friend buildFriend(ParseTreeNode friendDeclarationNode) { friendDeclarationNode.verifyType(CALTreeParserTokenTypes.LITERAL_friend); ParseTreeNode friendModuleNameNode = friendDeclarationNode.firstChild(); SourceModel.Name.Module friendModuleName = buildModuleName(friendModuleNameNode); return SourceModel.Friend.makeAnnotated(friendModuleName, friendDeclarationNode.getAssemblySourceRange()); } static SourceModel.TypeClassDefn.ClassMethodDefn buildClassMethodDefn(ParseTreeNode classMethodNode) { classMethodNode.verifyType(CALTreeParserTokenTypes.CLASS_METHOD); ParseTreeNode optionalCALDocNode = classMethodNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.ClassMethod caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.ClassMethod.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode scopeNode = optionalCALDocNode.nextSibling(); Scope scope = CALTypeChecker.getScopeModifier(scopeNode); boolean isScopeExplicitlySpecified = isScopeExplicitlySpecified(scopeNode); ParseTreeNode classMethodNameNode = scopeNode.nextSibling(); classMethodNameNode.verifyType(CALTreeParserTokenTypes.VAR_ID); ParseTreeNode typeSignatureNode = classMethodNameNode.nextSibling(); ParseTreeNode defaultClassMethodNameNode = typeSignatureNode.nextSibling(); final SourceModel.Name.Function defaultClassMethodName; if (defaultClassMethodNameNode != null) { defaultClassMethodName = buildFunctionName(defaultClassMethodNameNode); } else { defaultClassMethodName = null; } SourceRange bodySourceRange; { final SourceRange wholeExpression = classMethodNode.getAssemblySourceRange(); final SourceRange classMethodNameSourceRange = classMethodNameNode.getAssemblySourceRange(); if (wholeExpression != null && classMethodNameSourceRange != null){ final SourcePosition startOfLine = new SourcePosition(classMethodNameSourceRange.getStartLine(), 1, classMethodNameSourceRange.getSourceName()); bodySourceRange = new SourceRange(startOfLine, wholeExpression.getEndSourcePosition()); } else{ bodySourceRange = null; } } return SourceModel.TypeClassDefn.ClassMethodDefn.makeAnnotated(caldocComment, classMethodNameNode.getText(), scope, isScopeExplicitlySpecified, buildTypeSignature(typeSignatureNode), defaultClassMethodName, classMethodNameNode.getAssemblySourceRange(), bodySourceRange); } static SourceModel.TypeClassDefn buildTypeClassDefn(ParseTreeNode typeClassDefnNode) { typeClassDefnNode.verifyType(CALTreeParserTokenTypes.TYPE_CLASS_DEFN); ParseTreeNode optionalCALDocNode = typeClassDefnNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.TypeClass caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.TypeClass.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode scopeNode = optionalCALDocNode.nextSibling(); Scope scope = CALTypeChecker.getScopeModifier(scopeNode); boolean isScopeExplicitlySpecified = isScopeExplicitlySpecified(scopeNode); ParseTreeNode contextListNode = scopeNode.nextSibling(); contextListNode.verifyType(CALTreeParserTokenTypes.CLASS_CONTEXT_LIST, CALTreeParserTokenTypes.CLASS_CONTEXT_SINGLETON, CALTreeParserTokenTypes.CLASS_CONTEXT_NOTHING); SourceModel.Constraint.TypeClass[] parentClassConstraints = new SourceModel.Constraint.TypeClass[contextListNode.getNumberOfChildren()]; int parentN = 0; for (final ParseTreeNode contextNode : contextListNode) { parentClassConstraints[parentN] = buildTypeClassConstraint(contextNode); ++parentN; } ParseTreeNode typeClassNameNode = contextListNode.nextSibling(); typeClassNameNode.verifyType(CALTreeParserTokenTypes.CONS_ID); String typeClassName = typeClassNameNode.getText(); ParseTreeNode typeVarNode = typeClassNameNode.nextSibling(); typeVarNode.verifyType(CALTreeParserTokenTypes.VAR_ID); ParseTreeNode classMethodListNode = typeVarNode.nextSibling(); classMethodListNode.verifyType(CALTreeParserTokenTypes.CLASS_METHOD_LIST); SourceModel.TypeClassDefn.ClassMethodDefn[] classMethods = new SourceModel.TypeClassDefn.ClassMethodDefn[classMethodListNode.getNumberOfChildren()]; int methodN = 0; for (final ParseTreeNode classMethodNode : classMethodListNode) { classMethods[methodN] = buildClassMethodDefn(classMethodNode); ++methodN; } SourceRange bodySourceRange; { final SourceRange wholeExpression = typeClassDefnNode.getAssemblySourceRange(); final SourceRange typeClassNameSourceRange = typeClassNameNode.getAssemblySourceRange(); if (wholeExpression != null && typeClassNameSourceRange != null){ final SourcePosition startOfLine = new SourcePosition(typeClassNameSourceRange.getStartLine(), 1, typeClassNameSourceRange.getSourceName()); bodySourceRange = new SourceRange(startOfLine, wholeExpression.getEndSourcePosition()); } else{ bodySourceRange = null; } } return SourceModel.TypeClassDefn.makeAnnotated(caldocComment, typeClassName, buildTypeVarName(typeVarNode), scope, isScopeExplicitlySpecified, parentClassConstraints ,classMethods, typeClassNameNode.getAssemblySourceRange(), bodySourceRange, contextListNode.getType() == CALTreeParserTokenTypes.CLASS_CONTEXT_LIST); } static SourceModel.InstanceDefn.InstanceTypeCons buildInstanceTypeCons(ParseTreeNode instanceTypeConsNode) { switch(instanceTypeConsNode.getType()) { case CALTreeParserTokenTypes.GENERAL_TYPE_CONSTRUCTOR: case CALTreeParserTokenTypes.UNPARENTHESIZED_TYPE_CONSTRUCTOR: { ParseTreeNode typeConsNameNode = instanceTypeConsNode.firstChild(); final int nTypeVars = instanceTypeConsNode.getNumberOfChildren() - 1; SourceModel.Name.TypeVar[] typeVarNames = new SourceModel.Name.TypeVar[nTypeVars]; int i = 0; for (final ParseTreeNode typeVarNode : typeConsNameNode.nextSiblings()) { typeVarNames[i] = buildTypeVarName(typeVarNode); ++i; } return SourceModel.InstanceDefn.InstanceTypeCons.TypeCons.makeAnnotated(buildTypeConsName(typeConsNameNode), typeVarNames, typeConsNameNode.getAssemblySourceRange(), instanceTypeConsNode.getAssemblySourceRange(), instanceTypeConsNode.getType() == CALTreeParserTokenTypes.GENERAL_TYPE_CONSTRUCTOR); } case CALTreeParserTokenTypes.FUNCTION_TYPE_CONSTRUCTOR: { ParseTreeNode domainNameNode = instanceTypeConsNode.firstChild(); ParseTreeNode codomainNameNode = instanceTypeConsNode.getChild(1); return SourceModel.InstanceDefn.InstanceTypeCons.Function.makeAnnotated(buildTypeVarName(domainNameNode), buildTypeVarName(codomainNameNode), instanceTypeConsNode.getAssemblySourceRange(), instanceTypeConsNode.getSourceRange()); } case CALTreeParserTokenTypes.UNIT_TYPE_CONSTRUCTOR: { return SourceModel.InstanceDefn.InstanceTypeCons.Unit.makeAnnotated(instanceTypeConsNode.getAssemblySourceRange()); } case CALTreeParserTokenTypes.LIST_TYPE_CONSTRUCTOR: { return SourceModel.InstanceDefn.InstanceTypeCons.List.makeAnnotated(buildTypeVarName(instanceTypeConsNode.firstChild()), instanceTypeConsNode.getAssemblySourceRange()); } case CALTreeParserTokenTypes.RECORD_TYPE_CONSTRUCTOR: { return SourceModel.InstanceDefn.InstanceTypeCons.Record.makeAnnotated(buildTypeVarName(instanceTypeConsNode.firstChild()), instanceTypeConsNode.firstChild().getAssemblySourceRange(), instanceTypeConsNode.getSourceRange()); } default: { throw new IllegalStateException("Unexpected parse tree node " + instanceTypeConsNode.toDebugString() + "."); } } } static SourceModel.InstanceDefn buildInstanceDefn(ParseTreeNode instanceDefnNode) { instanceDefnNode.verifyType(CALTreeParserTokenTypes.INSTANCE_DEFN); ParseTreeNode optionalCALDocNode = instanceDefnNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.Instance caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.Instance.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode instanceNameNode = optionalCALDocNode.nextSibling(); instanceNameNode.verifyType(CALTreeParserTokenTypes.INSTANCE_NAME); ParseTreeNode contextListNode = instanceNameNode.firstChild(); contextListNode.verifyType(CALTreeParserTokenTypes.CLASS_CONTEXT_LIST, CALTreeParserTokenTypes.CLASS_CONTEXT_SINGLETON, CALTreeParserTokenTypes.CLASS_CONTEXT_NOTHING); SourceModel.Constraint.TypeClass[] constraints = new SourceModel.Constraint.TypeClass[contextListNode.getNumberOfChildren()]; int i = 0; for (final ParseTreeNode contextNode : contextListNode) { constraints[i] = buildTypeClassConstraint(contextNode); ++i; } ParseTreeNode typeClassNameNode = contextListNode.nextSibling(); SourceModel.Name.TypeClass typeClassName = buildTypeClassName(typeClassNameNode); SourceModel.InstanceDefn.InstanceTypeCons instanceTypeCons = buildInstanceTypeCons(typeClassNameNode.nextSibling()); ParseTreeNode instanceMethodListNode = instanceNameNode.nextSibling(); instanceMethodListNode.verifyType(CALTreeParserTokenTypes.INSTANCE_METHOD_LIST); SourceModel.InstanceDefn.InstanceMethod[] instanceMethods = new SourceModel.InstanceDefn.InstanceMethod[instanceMethodListNode.getNumberOfChildren()]; i = 0; for (final ParseTreeNode instanceMethodNode : instanceMethodListNode) { instanceMethodNode.verifyType(CALTreeParserTokenTypes.INSTANCE_METHOD); ParseTreeNode optionalInstanceMethodCALDocNode = instanceMethodNode.firstChild(); optionalInstanceMethodCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.InstanceMethod instanceMethodCALDocComment = null; ParseTreeNode instanceMethodCALDocNode = optionalInstanceMethodCALDocNode.firstChild(); if (instanceMethodCALDocNode != null) { instanceMethodCALDocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = instanceMethodCALDocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); instanceMethodCALDocComment = SourceModel.CALDoc.Comment.InstanceMethod.makeAnnotated(desc, blocks, instanceMethodCALDocNode.getAssemblySourceRange()); } ParseTreeNode classMethodNameNode = instanceMethodNode.getChild(1); ParseTreeNode resolvingFunctionNameNode = instanceMethodNode.getChild(2); instanceMethods[i] = SourceModel.InstanceDefn.InstanceMethod.makeAnnotated(instanceMethodCALDocComment, classMethodNameNode.getText(), buildFunctionName(resolvingFunctionNameNode), resolvingFunctionNameNode.getAssemblySourceRange(), classMethodNameNode.getAssemblySourceRange()); ++i; } return SourceModel.InstanceDefn.makeAnnotated(caldocComment, typeClassName, instanceTypeCons, constraints, instanceMethods, instanceDefnNode.getAssemblySourceRange(), contextListNode.getType() == CALTreeParserTokenTypes.CLASS_CONTEXT_LIST); } static SourceModel.TypeConstructorDefn.AlgebraicType.DataConsDefn buildDataConsDefn(ParseTreeNode dataConsDefnNode) { dataConsDefnNode.verifyType(CALTreeParserTokenTypes.DATA_CONSTRUCTOR_DEFN); ParseTreeNode optionalCALDocNode = dataConsDefnNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.DataCons caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.DataCons.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode scopeNode = optionalCALDocNode.nextSibling(); Scope scope = CALTypeChecker.getScopeModifier(scopeNode); boolean isScopeExplicitlySpecified = isScopeExplicitlySpecified(scopeNode); ParseTreeNode dataConsNameNode = scopeNode.nextSibling(); String dataConsName = dataConsNameNode.getText(); ParseTreeNode dataConsArgListNode = dataConsNameNode.nextSibling(); dataConsArgListNode.verifyType(CALTreeParserTokenTypes.DATA_CONSTRUCTOR_ARG_LIST); SourceModel.TypeConstructorDefn.AlgebraicType.DataConsDefn.TypeArgument[] argTypes = new SourceModel.TypeConstructorDefn.AlgebraicType.DataConsDefn.TypeArgument[dataConsArgListNode.getNumberOfChildren()]; int argN = 0; for (final ParseTreeNode dataConsArgNode : dataConsArgListNode) { dataConsArgNode.verifyType(CALTreeParserTokenTypes.DATA_CONSTRUCTOR_NAMED_ARG); // Get the name. ParseTreeNode dataConsArgNameNode = dataConsArgNode.firstChild(); SourceModel.Name.Field fieldName = buildFieldName(dataConsArgNameNode); // Get the type node. ParseTreeNode maybePlingTypeExprNode = dataConsArgNameNode.nextSibling(); ParseTreeNode typeExprNode; boolean isStrict; if (maybePlingTypeExprNode.getType() == CALTreeParserTokenTypes.STRICT_ARG) { typeExprNode = maybePlingTypeExprNode.firstChild(); isStrict = true; } else { typeExprNode = maybePlingTypeExprNode; isStrict = false; } argTypes[argN] = SourceModel.TypeConstructorDefn.AlgebraicType.DataConsDefn.TypeArgument.makeAnnotated(fieldName, buildTypeExprDefn(typeExprNode), isStrict,dataConsArgNode.getAssemblySourceRange()); ++argN; } SourceRange bodySourceRange; { final SourceRange wholeExpression = dataConsDefnNode.getAssemblySourceRange(); final SourceRange dataConsNameSourceRange = dataConsNameNode.getAssemblySourceRange(); if (wholeExpression != null && dataConsNameSourceRange != null){ final SourcePosition startOfLine = new SourcePosition(dataConsNameSourceRange.getStartLine(), 1, dataConsNameSourceRange.getSourceName()); bodySourceRange = new SourceRange(startOfLine, wholeExpression.getEndSourcePosition()); } else{ bodySourceRange = null; } } return SourceModel.TypeConstructorDefn.AlgebraicType.DataConsDefn.makeAnnotated(caldocComment, dataConsName, scope, isScopeExplicitlySpecified, argTypes, dataConsNameNode.getAssemblySourceRange(), bodySourceRange); } static SourceModel.TypeConstructorDefn.AlgebraicType buildAlgebraicTypeDefn(ParseTreeNode algebraicTypeDefnNode) { algebraicTypeDefnNode.verifyType(CALTreeParserTokenTypes.DATA_DECLARATION); ParseTreeNode optionalCALDocNode = algebraicTypeDefnNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.TypeCons caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.TypeCons.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode accessModifierNode = optionalCALDocNode.nextSibling(); Scope scope = CALTypeChecker.getScopeModifier(accessModifierNode); boolean isScopeExplicitlySpecified = isScopeExplicitlySpecified(accessModifierNode); ParseTreeNode typeNameNode = accessModifierNode.nextSibling(); typeNameNode.verifyType(CALTreeParserTokenTypes.CONS_ID); String typeName = typeNameNode.getText(); ParseTreeNode typeParamListNode = typeNameNode.nextSibling(); typeParamListNode.verifyType(CALTreeParserTokenTypes.TYPE_CONS_PARAM_LIST); SourceModel.Name.TypeVar[] typeParameters = new SourceModel.Name.TypeVar[typeParamListNode.getNumberOfChildren()]; int paramN = 0; for (final ParseTreeNode typeVarNode : typeParamListNode) { typeVarNode.verifyType(CALTreeParserTokenTypes.VAR_ID); typeParameters[paramN] = buildTypeVarName(typeVarNode); ++paramN; } //Data constructor names must be unique within the entire module. ParseTreeNode dataConsDefnListNode = typeNameNode.nextSibling().nextSibling(); dataConsDefnListNode.verifyType(CALTreeParserTokenTypes.DATA_CONSTRUCTOR_DEFN_LIST); SourceModel.TypeConstructorDefn.AlgebraicType.DataConsDefn[] dataConstructors = new SourceModel.TypeConstructorDefn.AlgebraicType.DataConsDefn[dataConsDefnListNode.getNumberOfChildren()]; int dcN = 0; for (final ParseTreeNode dataConsDefnNode : dataConsDefnListNode) { dataConstructors[dcN] = buildDataConsDefn(dataConsDefnNode); ++dcN; } ParseTreeNode derivingClauseNode = dataConsDefnListNode.nextSibling(); SourceModel.Name.TypeClass[] derivingClauseTypeClassNames = buildDerivingClauseTypeClassNames(derivingClauseNode); SourceRange bodySourceRange; { final SourceRange wholeExpression = algebraicTypeDefnNode.getAssemblySourceRange(); final SourceRange accessModifierSourceRange = accessModifierNode.getAssemblySourceRange(); if (wholeExpression != null && accessModifierSourceRange != null){ final SourcePosition startOfLine = new SourcePosition(accessModifierSourceRange.getStartLine(), 1, accessModifierSourceRange.getSourceName()); bodySourceRange = new SourceRange(startOfLine, wholeExpression.getEndSourcePosition()); } else if (wholeExpression != null){ // not quite right but better than nothing. // This will be cleaned up when we // fix up all the source position problems. bodySourceRange = wholeExpression; } else{ bodySourceRange = null; } } return SourceModel.TypeConstructorDefn.AlgebraicType.makeAnnotated(caldocComment, typeName, scope, isScopeExplicitlySpecified, typeParameters, dataConstructors, derivingClauseTypeClassNames, typeNameNode.getAssemblySourceRange(), bodySourceRange); } static SourceModel.TypeConstructorDefn.ForeignType buildForeignTypeDefn(ParseTreeNode foreignTypeDefnNode) { foreignTypeDefnNode.verifyType(CALTreeParserTokenTypes.FOREIGN_DATA_DECLARATION); ParseTreeNode optionalCALDocNode = foreignTypeDefnNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.TypeCons caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.TypeCons.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode implementationScopeNode = optionalCALDocNode.nextSibling(); Scope implementationScope = CALTypeChecker.getScopeModifier(implementationScopeNode); boolean isImplementationScopeExplicitlySpecified = isScopeExplicitlySpecified(implementationScopeNode); ParseTreeNode externalNameNode = implementationScopeNode.nextSibling(); externalNameNode.verifyType(CALTreeParserTokenTypes.STRING_LITERAL); String externalName = StringEncoder.unencodeString(externalNameNode.getText ()); final SourceRange externalNameSourceRange = externalNameNode.getSourceRange(); ParseTreeNode accessModifierNode = externalNameNode.nextSibling(); Scope scope = CALTypeChecker.getScopeModifier(accessModifierNode); boolean isScopeExplicitlySpecified = isScopeExplicitlySpecified(accessModifierNode); ParseTreeNode typeNameNode = accessModifierNode.nextSibling(); typeNameNode.verifyType(CALTreeParserTokenTypes.CONS_ID); String typeName = typeNameNode.getText(); ParseTreeNode derivingClauseNode = typeNameNode.nextSibling(); SourceModel.Name.TypeClass[] derivingClauseTypeClassNames = buildDerivingClauseTypeClassNames(derivingClauseNode); SourceRange bodySourceRange; { final SourceRange wholeExpressionSourceRange = foreignTypeDefnNode.getAssemblySourceRange(); final SourceRange externalNameAssemblySourceRange = externalNameNode.getAssemblySourceRange(); if (wholeExpressionSourceRange != null && externalNameAssemblySourceRange != null){ final SourcePosition startOfLine = new SourcePosition(externalNameAssemblySourceRange.getStartLine(), 1, externalNameAssemblySourceRange.getSourceName()); bodySourceRange = new SourceRange(startOfLine, wholeExpressionSourceRange.getEndSourcePosition()); } else{ bodySourceRange = null; } } return SourceModel.TypeConstructorDefn.ForeignType.makeAnnotated(caldocComment, typeName, scope, isScopeExplicitlySpecified, externalName, externalNameSourceRange, implementationScope, isImplementationScopeExplicitlySpecified, derivingClauseTypeClassNames, typeNameNode.getAssemblySourceRange(), bodySourceRange); } static SourceModel.Name.TypeClass[] buildDerivingClauseTypeClassNames(ParseTreeNode derivingClauseNode) { if (derivingClauseNode == null) { return null; } derivingClauseNode.verifyType(CALTreeParserTokenTypes.LITERAL_deriving); SourceModel.Name.TypeClass[] derivingClauseTypeClassNames = new SourceModel.Name.TypeClass[derivingClauseNode.getNumberOfChildren()]; int derivingClauseN = 0; for (final ParseTreeNode derivingClauseNameNode : derivingClauseNode) { derivingClauseTypeClassNames[derivingClauseN] = buildTypeClassName(derivingClauseNameNode); ++derivingClauseN; } return derivingClauseTypeClassNames; } static SourceModel.FunctionTypeDeclaration buildFunctionTypeDeclaration(ParseTreeNode topLevelTypeDeclarationNode) { topLevelTypeDeclarationNode.verifyType( CALTreeParserTokenTypes.TOP_LEVEL_TYPE_DECLARATION); ParseTreeNode optionalCALDocNode = topLevelTypeDeclarationNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.Function caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.Function.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode typeDeclarationNode = optionalCALDocNode.nextSibling(); ParseTreeNode functionNameNode = typeDeclarationNode.firstChild(); functionNameNode.verifyType(CALTreeParserTokenTypes.VAR_ID); ParseTreeNode declaredTypeNode = functionNameNode.nextSibling(); SourceRange bodySourceRange; { final SourceRange wholeExpression = topLevelTypeDeclarationNode.getAssemblySourceRange(); final SourceRange classMethodNameSourceRange = typeDeclarationNode.getAssemblySourceRange(); if (wholeExpression != null && classMethodNameSourceRange != null){ final SourcePosition startOfLine = new SourcePosition(classMethodNameSourceRange.getStartLine(), 1, classMethodNameSourceRange.getSourceName()); bodySourceRange = new SourceRange(startOfLine, wholeExpression.getEndSourcePosition()); } else{ bodySourceRange = null; } } return SourceModel.FunctionTypeDeclaration.makeAnnotated(caldocComment, functionNameNode.getText(), buildTypeSignature(declaredTypeNode), functionNameNode.getAssemblySourceRange(), bodySourceRange); } static SourceModel.FunctionDefn.Algebraic buildAlgebraicFunctionDefn(ParseTreeNode topLevelFunctionDefnNode) { topLevelFunctionDefnNode.verifyType(CALTreeParserTokenTypes.TOP_LEVEL_FUNCTION_DEFN); ParseTreeNode optionalCALDocNode = topLevelFunctionDefnNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.Function caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.Function.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode accessModifierNode = optionalCALDocNode.nextSibling(); Scope scope = CALTypeChecker.getScopeModifier(accessModifierNode); boolean isScopeExplicitlySpecified = isScopeExplicitlySpecified(accessModifierNode); ParseTreeNode functionNameNode = accessModifierNode.nextSibling(); functionNameNode.verifyType(CALTreeParserTokenTypes.VAR_ID); String functionName = functionNameNode.getText(); ParseTreeNode paramListNode = functionNameNode.nextSibling(); paramListNode.verifyType(CALTreeParserTokenTypes.FUNCTION_PARAM_LIST); final int nParams = paramListNode.getNumberOfChildren(); int paramN = 0; SourceModel.Parameter[] parameters = new SourceModel.Parameter[nParams]; for (final ParseTreeNode varNode : paramListNode) { parameters[paramN] = SourceModel.Parameter.makeAnnotated(varNode.getText(), varNode.getType() == CALTreeParserTokenTypes.STRICT_PARAM, varNode.getAssemblySourceRange()); ++paramN; } ParseTreeNode exprNode = paramListNode.nextSibling(); SourceModel.Expr definingExpr = buildExpr(exprNode); ParseTreeNode accessModifierTokenNode = accessModifierNode.firstChild(); final SourceRange sourceRange = topLevelFunctionDefnNode.getAssemblySourceRange(); SourceRange sourceRangeExcludingCaldoc = null; SourceRange functionNameNodeRange = functionNameNode.getSourceRange(); SourceRange accessModifierTokenNodeRange = null; if(accessModifierTokenNode != null) { accessModifierTokenNodeRange = accessModifierTokenNode.getAssemblySourceRange(); } if(sourceRange != null) { if(accessModifierTokenNodeRange != null) { sourceRangeExcludingCaldoc = new SourceRange(accessModifierTokenNodeRange.getStartSourcePosition(), sourceRange.getEndSourcePosition()); } else { sourceRangeExcludingCaldoc = new SourceRange(functionNameNodeRange.getStartSourcePosition(), sourceRange.getEndSourcePosition()); } } return SourceModel.FunctionDefn.Algebraic.makeAnnotated(caldocComment, functionName, scope, isScopeExplicitlySpecified, parameters, definingExpr, sourceRange, sourceRangeExcludingCaldoc, functionNameNode.getAssemblySourceRange()); } static SourceModel.FunctionDefn.Foreign buildForeignFunctionDefn(ParseTreeNode foreignFunctionDeclarationNode) { foreignFunctionDeclarationNode.verifyType(CALTreeParserTokenTypes.FOREIGN_FUNCTION_DECLARATION); final SourceRange sourceRange = foreignFunctionDeclarationNode.getAssemblySourceRange(); SourceRange sourceRangeExcludingCaldoc = null; SourceRange declarationNodeRange = foreignFunctionDeclarationNode.getSourceRange(); if(sourceRange != null && declarationNodeRange != null) { sourceRangeExcludingCaldoc = new SourceRange(declarationNodeRange.getStartSourcePosition(), sourceRange.getEndSourcePosition()); } ParseTreeNode optionalCALDocNode = foreignFunctionDeclarationNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.Function caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.Function.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode externalNameNode = optionalCALDocNode.nextSibling(); externalNameNode.verifyType(CALTreeParserTokenTypes.STRING_LITERAL); String externalName = StringEncoder.unencodeString(externalNameNode.getText ()); final SourceRange externalNameSourceRange = externalNameNode.getSourceRange(); ParseTreeNode accessModifierNode = externalNameNode.nextSibling(); Scope scope = CALTypeChecker.getScopeModifier(accessModifierNode); boolean isScopeExplicitlySpecified = isScopeExplicitlySpecified(accessModifierNode); ParseTreeNode typeDeclarationNode = accessModifierNode.nextSibling(); typeDeclarationNode.verifyType(CALTreeParserTokenTypes.TYPE_DECLARATION); ParseTreeNode functionNameNode = typeDeclarationNode.firstChild(); functionNameNode.verifyType(CALTreeParserTokenTypes.VAR_ID); String functionName = functionNameNode.getText(); SourceModel.TypeSignature declaredType = buildTypeSignature(functionNameNode.nextSibling()); return SourceModel.FunctionDefn.Foreign.makeAnnotated(caldocComment, functionName, scope, isScopeExplicitlySpecified, externalName, externalNameSourceRange, declaredType, sourceRange, sourceRangeExcludingCaldoc, functionNameNode.getAssemblySourceRange()); } static SourceModel.FunctionDefn.Primitive buildPrimitiveFunctionDefn(ParseTreeNode primitiveFunctionNode) { primitiveFunctionNode.verifyType(CALTreeParserTokenTypes.PRIMITIVE_FUNCTION_DECLARATION); ParseTreeNode optionalCALDocNode = primitiveFunctionNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.Function caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.Function.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode accessModifierNode = optionalCALDocNode.nextSibling(); Scope scope = CALTypeChecker.getScopeModifier(accessModifierNode); boolean isScopeExplicitlySpecified = isScopeExplicitlySpecified(accessModifierNode); ParseTreeNode typeDeclarationNode = accessModifierNode.nextSibling(); typeDeclarationNode.verifyType(CALTreeParserTokenTypes.TYPE_DECLARATION); ParseTreeNode functionNameNode = typeDeclarationNode.firstChild(); functionNameNode.verifyType(CALTreeParserTokenTypes.VAR_ID); String functionName = functionNameNode.getText(); SourceModel.TypeSignature declaredType = buildTypeSignature(functionNameNode.nextSibling()); final SourceRange sourceRange = primitiveFunctionNode.getAssemblySourceRange(); SourceRange primitiveFunctionNodeRange = primitiveFunctionNode.getSourceRange(); SourceRange sourceRangeExcludingCaldoc = null; if(sourceRange != null && primitiveFunctionNodeRange != null) { sourceRangeExcludingCaldoc = new SourceRange(primitiveFunctionNodeRange.getStartSourcePosition(), sourceRange.getEndSourcePosition()); } return SourceModel.FunctionDefn.Primitive.makeAnnotated( caldocComment, functionName, scope, isScopeExplicitlySpecified, declaredType, sourceRange, sourceRangeExcludingCaldoc, functionNameNode.getAssemblySourceRange()); } static SourceModel.Constraint.TypeClass buildTypeClassConstraint(ParseTreeNode contextNode) { contextNode.verifyType(CALTreeParserTokenTypes.CLASS_CONTEXT); ParseTreeNode typeClassNameNode = contextNode.firstChild(); typeClassNameNode.verifyType(CALTreeParserTokenTypes.QUALIFIED_CONS); ParseTreeNode varNameNode = typeClassNameNode.nextSibling(); varNameNode.verifyType(CALTreeParserTokenTypes.VAR_ID); return SourceModel.Constraint.TypeClass.makeAnnotated(buildTypeClassName(typeClassNameNode), buildTypeVarName(varNameNode), contextNode.getAssemblySourceRange()); } static SourceModel.TypeSignature buildTypeSignature(ParseTreeNode typeSignatureNode) { typeSignatureNode.verifyType(CALTreeParserTokenTypes.TYPE_SIGNATURE); ParseTreeNode typeContextListNode = typeSignatureNode.firstChild(); typeContextListNode.verifyType(CALTreeParserTokenTypes.TYPE_CONTEXT_LIST, CALTreeParserTokenTypes.TYPE_CONTEXT_NOTHING, CALTreeParserTokenTypes.TYPE_CONTEXT_SINGLETON); final int nConstraints = typeContextListNode.getNumberOfChildren(); SourceModel.Constraint[] constraints = new SourceModel.Constraint[nConstraints]; int i = 0; for (final ParseTreeNode contextNode : typeContextListNode) { switch (contextNode.getType()) { case CALTreeParserTokenTypes.CLASS_CONTEXT : { constraints[i] = buildTypeClassConstraint(contextNode); break; } case CALTreeParserTokenTypes.LACKS_FIELD_CONTEXT: { ParseTreeNode recordVarNameNode = contextNode.firstChild(); recordVarNameNode.verifyType(CALTreeParserTokenTypes.VAR_ID); ParseTreeNode lacksFieldNameNode = recordVarNameNode.nextSibling(); SourceModel.Name.Field lacksFieldName = buildFieldName(lacksFieldNameNode); constraints[i] = SourceModel.Constraint.Lacks.makeAnnotated(buildTypeVarName(recordVarNameNode), lacksFieldName, contextNode.getAssemblySourceRange()); break; } default: { throw new IllegalStateException("Unexpected parse tree node " + contextNode.toDebugString() + "."); } } ++i; } ParseTreeNode typeExprNode = typeContextListNode.nextSibling(); return SourceModel.TypeSignature.make(constraints, buildTypeExprDefn(typeExprNode), typeContextListNode.getType() == CALTreeParserTokenTypes.TYPE_CONTEXT_LIST); } static SourceModel.LocalDefn.Function.Definition buildLocalFunctionDefn(ParseTreeNode localFunctionNode) { localFunctionNode.verifyType(CALTreeParserTokenTypes.LET_DEFN); ParseTreeNode optionalCALDocNode = localFunctionNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.Function caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.Function.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode functionNameNode = optionalCALDocNode.nextSibling(); functionNameNode.verifyType(CALTreeParserTokenTypes.VAR_ID); String functionName = functionNameNode.getText(); SourceRange functionNameSourceRange = functionNameNode.getSourceRange(); ParseTreeNode paramListNode = functionNameNode.nextSibling(); paramListNode.verifyType(CALTreeParserTokenTypes.FUNCTION_PARAM_LIST); final int nParams = paramListNode.getNumberOfChildren(); int paramN = 0; SourceModel.Parameter[] parameters = new SourceModel.Parameter[nParams]; for (final ParseTreeNode varNode : paramListNode) { parameters[paramN] = SourceModel.Parameter.makeAnnotated(varNode.getText(), varNode.getType() == CALTreeParserTokenTypes.STRICT_PARAM, varNode.getAssemblySourceRange()); ++paramN; } ParseTreeNode exprNode = paramListNode.nextSibling(); SourceModel.Expr definingExpr = buildExpr(exprNode); SourceRange sourceRange = localFunctionNode.getAssemblySourceRange(); SourceRange sourceRangeExcludingCaldoc = null; SourceRange functionNameNodeRange = functionNameNode.getSourceRange(); if(sourceRange != null && functionNameNodeRange != null) { sourceRangeExcludingCaldoc = new SourceRange(functionNameNodeRange.getStartSourcePosition(), sourceRange.getEndSourcePosition()); } return SourceModel.LocalDefn.Function.Definition.makeAnnotated(caldocComment, functionName, functionNameSourceRange, parameters, definingExpr, sourceRange, sourceRangeExcludingCaldoc); } static SourceModel.LocalDefn.Function.TypeDeclaration buildLocalFunctionTypeDeclaration(ParseTreeNode localTypeDeclarationNode) { localTypeDeclarationNode.verifyType(CALTreeParserTokenTypes.LET_DEFN_TYPE_DECLARATION); ParseTreeNode optionalCALDocNode = localTypeDeclarationNode.firstChild(); optionalCALDocNode.verifyType(CALTreeParserTokenTypes.OPTIONAL_CALDOC_COMMENT); SourceModel.CALDoc.Comment.Function caldocComment = null; ParseTreeNode caldocNode = optionalCALDocNode.firstChild(); if (caldocNode != null) { caldocNode.verifyType(CALTreeParserTokenTypes.CALDOC_COMMENT); ParseTreeNode descNode = caldocNode.firstChild(); SourceModel.CALDoc.TextBlock desc = buildCALDocDescriptionBlock(descNode); ParseTreeNode taggedBlocksNode = descNode.nextSibling(); SourceModel.CALDoc.TaggedBlock[] blocks = buildCALDocTaggedBlocks(taggedBlocksNode); caldocComment = SourceModel.CALDoc.Comment.Function.makeAnnotated(desc, blocks, caldocNode.getAssemblySourceRange()); } ParseTreeNode typeDeclarationNode = optionalCALDocNode.nextSibling(); typeDeclarationNode.verifyType( CALTreeParserTokenTypes.TYPE_DECLARATION); ParseTreeNode functionNameNode = typeDeclarationNode.firstChild(); functionNameNode.verifyType(CALTreeParserTokenTypes.VAR_ID); ParseTreeNode declaredTypeNode = functionNameNode.nextSibling(); return SourceModel.LocalDefn.Function.TypeDeclaration.makeAnnotated(caldocComment, functionNameNode.getText(), functionNameNode.getSourceRange(), buildTypeSignature(declaredTypeNode), localTypeDeclarationNode.getAssemblySourceRange()); } /** * Builds a source model representation of a local pattern match declaration. * @param localPatternMatchDeclNode the root of the parse tree representing a local pattern match declaration. * @return a source model representation of a local pattern match declaration. */ static SourceModel.LocalDefn.PatternMatch buildLocalPatternMatchDecl(final ParseTreeNode localPatternMatchDeclNode) { localPatternMatchDeclNode.verifyType(CALTreeParserTokenTypes.LET_PATTERN_MATCH_DECL); final SourceRange patternMatchDeclSourceRange = localPatternMatchDeclNode.getAssemblySourceRange(); ParseTreeNode fullPatternNode = localPatternMatchDeclNode.firstChild(); ParseTreeNode exprNode = fullPatternNode.nextSibling(); SourceModel.Expr expr = buildExpr(exprNode); switch (fullPatternNode.getType()) { case CALTreeParserTokenTypes.PATTERN_CONSTRUCTOR : { ParseTreeNode dataConsNameListNode = fullPatternNode.firstChild(); dataConsNameListNode.verifyType(CALTreeParserTokenTypes.DATA_CONSTRUCTOR_NAME_LIST, CALTreeParserTokenTypes.DATA_CONSTRUCTOR_NAME_SINGLETON); ParseTreeNode dataConsNameNode = dataConsNameListNode.firstChild(); SourceModel.Name.DataCons dataConsName = buildDataConsName(dataConsNameNode); ParseTreeNode argBindingsNode = dataConsNameListNode.nextSibling(); switch (argBindingsNode.getType()) { case CALTreeParserTokenTypes.PATTERN_VAR_LIST : { return SourceModel.LocalDefn.PatternMatch.UnpackDataCons.makeAnnotated(dataConsName, SourceModel.ArgBindings.Positional.make(buildPatterns(argBindingsNode)), expr, patternMatchDeclSourceRange); } case CALTreeParserTokenTypes.FIELD_BINDING_VAR_ASSIGNMENT_LIST : { return SourceModel.LocalDefn.PatternMatch.UnpackDataCons.makeAnnotated(dataConsName, SourceModel.ArgBindings.Matching.make(buildFieldPatterns(argBindingsNode)), expr, patternMatchDeclSourceRange); } default : { throw new IllegalStateException("Unexpected parse tree node " + argBindingsNode.toDebugString() + "."); } } } case CALTreeParserTokenTypes.COLON : return SourceModel.LocalDefn.PatternMatch.UnpackListCons.makeAnnotated(buildPattern(fullPatternNode.firstChild()), buildPattern(fullPatternNode.getChild(1)), expr, patternMatchDeclSourceRange, fullPatternNode.getSourceRange()); case CALTreeParserTokenTypes.TUPLE_CONSTRUCTOR : return SourceModel.LocalDefn.PatternMatch.UnpackTuple.makeAnnotated(buildPatterns(fullPatternNode), expr, patternMatchDeclSourceRange); case CALTreeParserTokenTypes.RECORD_PATTERN: { ParseTreeNode baseRecordPatternNode = fullPatternNode.firstChild(); baseRecordPatternNode.verifyType(CALTreeParserTokenTypes.BASE_RECORD_PATTERN); SourceModel.Pattern baseRecordPattern = null; if (baseRecordPatternNode.firstChild() != null) { baseRecordPattern = buildPattern(baseRecordPatternNode.firstChild()); } ParseTreeNode fieldBindingVarAssignmentListNode = baseRecordPatternNode.nextSibling(); SourceModel.FieldPattern[] fieldPatterns = buildFieldPatterns(fieldBindingVarAssignmentListNode); return SourceModel.LocalDefn.PatternMatch.UnpackRecord.makeAnnotated(baseRecordPattern, fieldPatterns, expr, patternMatchDeclSourceRange); } default: { throw new IllegalStateException("Unexpected parse tree node " + fullPatternNode.toDebugString() + "."); } } } static SourceModel.Expr.Let buildLetExpr(ParseTreeNode letExprNode) { letExprNode.verifyType(CALTreeParserTokenTypes.LITERAL_let); ParseTreeNode defnListNode = letExprNode.firstChild(); defnListNode.verifyType(CALTreeParserTokenTypes.LET_DEFN_LIST); //these are either local function definitions or local function type declarations final int nLocalDefns = defnListNode.getNumberOfChildren(); SourceModel.LocalDefn[] localDefinitions = new SourceModel.LocalDefn[nLocalDefns]; int i = 0; for (final ParseTreeNode defnNode : defnListNode) { switch (defnNode.getType()) { case CALTreeParserTokenTypes.LET_DEFN: { localDefinitions[i] = buildLocalFunctionDefn(defnNode); break; } case CALTreeParserTokenTypes.LET_DEFN_TYPE_DECLARATION: { localDefinitions[i] = buildLocalFunctionTypeDeclaration(defnNode); break; } case CALTreeParserTokenTypes.LET_PATTERN_MATCH_DECL: { localDefinitions[i] = buildLocalPatternMatchDecl(defnNode); break; } default: { throw new IllegalStateException("Unexpected parse tree node " + defnNode.toDebugString() + "."); } } ++i; } ParseTreeNode inExprNode = defnListNode.nextSibling(); return SourceModel.Expr.Let.make(localDefinitions, buildExpr(inExprNode)); } static SourceModel.Expr.Lambda buildLambdaExpr(ParseTreeNode lambdaExprNode) { lambdaExprNode.verifyType(CALTreeParserTokenTypes.LAMBDA_DEFN); ParseTreeNode paramListNode = lambdaExprNode.firstChild(); ParseTreeNode exprNode = paramListNode.nextSibling(); return SourceModel.Expr.Lambda.makeAnnotated(buildParameters(paramListNode), buildExpr(exprNode), lambdaExprNode.getAssemblySourceRange()); } static SourceModel.Parameter[] buildParameters(ParseTreeNode paramListNode) { paramListNode.verifyType(CALTreeParserTokenTypes.FUNCTION_PARAM_LIST); final int nParams = paramListNode.getNumberOfChildren(); int paramN = 0; SourceModel.Parameter[] parameters = new SourceModel.Parameter[nParams]; for (final ParseTreeNode paramNode : paramListNode) { parameters[paramN] = buildParameter(paramNode); ++paramN; } return parameters; } static SourceModel.Parameter buildParameter(ParseTreeNode parameterNode) { parameterNode.verifyType(CALTreeParserTokenTypes.STRICT_PARAM, CALTreeParserTokenTypes.LAZY_PARAM); boolean isStrict = parameterNode.getType() == CALTreeParserTokenTypes.STRICT_PARAM; return SourceModel.Parameter.makeAnnotated(parameterNode.getText(), isStrict, parameterNode.getAssemblySourceRange()); } static SourceModel.FieldPattern[] buildFieldPatterns(ParseTreeNode fieldBindingVarAssignmentListNode) { fieldBindingVarAssignmentListNode.verifyType(CALTreeParserTokenTypes.FIELD_BINDING_VAR_ASSIGNMENT_LIST); int nFieldPatterns = fieldBindingVarAssignmentListNode.getNumberOfChildren(); SourceModel.FieldPattern[] fieldPatterns = new SourceModel.FieldPattern[nFieldPatterns]; int i = 0; for (final ParseTreeNode fieldPatternNode : fieldBindingVarAssignmentListNode) { fieldPatternNode.verifyType(CALTreeParserTokenTypes.FIELD_BINDING_VAR_ASSIGNMENT); ParseTreeNode fieldNameNode = fieldPatternNode.firstChild(); SourceModel.Name.Field fieldName = buildFieldName(fieldNameNode); SourceModel.Pattern pattern = null; ParseTreeNode patternVarNode = fieldNameNode.nextSibling(); if (patternVarNode != null) { pattern = buildPattern(patternVarNode); } fieldPatterns[i] = SourceModel.FieldPattern.makeAnnotated(fieldName, pattern); ++i; } return fieldPatterns; } /** * Builds a source model representation of a field name from the given ParseTreeNode. * @param fieldNameNode the ParseTreeNode representing a field name. * @return a source model representation of the field name. */ static SourceModel.Name.Field buildFieldName(final ParseTreeNode fieldNameNode) { return SourceModel.Name.Field.makeAnnotated(FieldName.make(fieldNameNode.getText()), fieldNameNode.getAssemblySourceRange()); } static SourceModel.Pattern[] buildPatterns(ParseTreeNode patternListNode) { patternListNode.verifyType(CALTreeParserTokenTypes.PATTERN_VAR_LIST, CALTreeParserTokenTypes.TUPLE_CONSTRUCTOR); final int nPatterns = patternListNode.getNumberOfChildren(); SourceModel.Pattern[] patterns = new SourceModel.Pattern[nPatterns]; int i = 0; for (final ParseTreeNode patternNode : patternListNode) { patterns[i] = buildPattern(patternNode); ++i; } return patterns; } static SourceModel.Pattern buildPattern(ParseTreeNode patternNode) { patternNode.verifyType(CALTreeParserTokenTypes.VAR_ID, CALTreeParserTokenTypes.UNDERSCORE); if (patternNode.getType() == CALTreeParserTokenTypes.VAR_ID) { return SourceModel.Pattern.Var.makeAnnotated(patternNode.getText(), patternNode.getAssemblySourceRange()); } return SourceModel.Pattern.Wildcard.make(); } static SourceModel.Expr.Case.Alt buildCaseAlt(ParseTreeNode altNode) { altNode.verifyType(CALTreeParserTokenTypes.ALT); ParseTreeNode fullPatternNode = altNode.firstChild(); ParseTreeNode altExprNode = fullPatternNode.nextSibling(); SourceModel.Expr altExpr = buildExpr(altExprNode); switch (fullPatternNode.getType()) { case CALTreeParserTokenTypes.PATTERN_CONSTRUCTOR : { ParseTreeNode dataConsNameListNode = fullPatternNode.firstChild(); List<DataCons> dataConsNameList = new ArrayList<DataCons>(); for (final ParseTreeNode dataConsNameNode : dataConsNameListNode) { dataConsNameList.add(buildDataConsName(dataConsNameNode)); } SourceModel.Name.DataCons[] dataConsNameArray = dataConsNameList.toArray(new SourceModel.Name.DataCons[dataConsNameList.size()]); ParseTreeNode argBindingsNode = dataConsNameListNode.nextSibling(); switch (argBindingsNode.getType()) { case CALTreeParserTokenTypes.PATTERN_VAR_LIST : { return SourceModel.Expr.Case.Alt.UnpackDataCons.makeAnnotated(dataConsNameArray, buildPatterns(argBindingsNode), altExpr, altNode.getAssemblySourceRange(), dataConsNameListNode.getType() == CALTokenTypes.DATA_CONSTRUCTOR_NAME_LIST); } case CALTreeParserTokenTypes.FIELD_BINDING_VAR_ASSIGNMENT_LIST : { return SourceModel.Expr.Case.Alt.UnpackDataCons.makeAnnotated(dataConsNameArray, buildFieldPatterns(argBindingsNode), altExpr, altNode.getAssemblySourceRange(), dataConsNameListNode.getType() == CALTokenTypes.DATA_CONSTRUCTOR_NAME_LIST); } default : { throw new IllegalStateException("Unexpected parse tree node " + argBindingsNode.toDebugString() + "."); } } } case CALTreeParserTokenTypes.INT_PATTERN : { ParseTreeNode intListNode = fullPatternNode.firstChild(); BigInteger[] bigInts = new BigInteger[intListNode.getNumberOfChildren()]; int index = 0; for (final ParseTreeNode maybeMinusIntNode : intListNode) { boolean minus; ParseTreeNode intLiteralNode; if (maybeMinusIntNode.getType() == CALTreeParserTokenTypes.MINUS) { minus = true; intLiteralNode = maybeMinusIntNode.firstChild(); } else { minus = false; intLiteralNode = maybeMinusIntNode; } intLiteralNode.verifyType(CALTreeParserTokenTypes.INTEGER_LITERAL); String symbolText = intLiteralNode.getText(); if (minus) { symbolText = "-" + symbolText; } //may throw a NumberFormatException if unsuccessful in parsing the value. // This should never happen for nodes created by the parser. bigInts[index] = new BigInteger(symbolText); index++; } return SourceModel.Expr.Case.Alt.UnpackInt.make(bigInts, altExpr); } case CALTreeParserTokenTypes.CHAR_PATTERN : { ParseTreeNode charListNode = fullPatternNode.firstChild(); int nCharsInGroup = charListNode.getNumberOfChildren(); char[] chars = new char[nCharsInGroup]; int index = 0; for (final ParseTreeNode charNode : charListNode) { charNode.verifyType(CALTreeParserTokenTypes.CHAR_LITERAL); chars[index] = StringEncoder.unencodeChar(charNode.getText()); index++; } return SourceModel.Expr.Case.Alt.UnpackChar.make(chars, altExpr); } case CALTreeParserTokenTypes.LIST_CONSTRUCTOR : return SourceModel.Expr.Case.Alt.UnpackListNil.makeAnnotated(altExpr, fullPatternNode.getAssemblySourceRange()); case CALTreeParserTokenTypes.COLON : return SourceModel.Expr.Case.Alt.UnpackListCons.makeAnnotated(buildPattern(fullPatternNode.firstChild()), buildPattern(fullPatternNode.getChild(1)), altExpr, fullPatternNode.getAssemblySourceRange(), fullPatternNode.getSourceRange()); case CALTreeParserTokenTypes.UNDERSCORE : return SourceModel.Expr.Case.Alt.Default.makeAnnotated(altExpr, fullPatternNode.getAssemblySourceRange()); case CALTreeParserTokenTypes.TUPLE_CONSTRUCTOR : return SourceModel.Expr.Case.Alt.UnpackTuple.make(buildPatterns(fullPatternNode), altExpr); case CALTreeParserTokenTypes.RECORD_PATTERN: { ParseTreeNode baseRecordPatternNode = fullPatternNode.firstChild(); baseRecordPatternNode.verifyType(CALTreeParserTokenTypes.BASE_RECORD_PATTERN); SourceModel.Pattern baseRecordPattern = null; if (baseRecordPatternNode.firstChild() != null) { baseRecordPattern = buildPattern(baseRecordPatternNode.firstChild()); } ParseTreeNode fieldBindingVarAssignmentListNode = baseRecordPatternNode.nextSibling(); SourceModel.FieldPattern[] fieldPatterns = buildFieldPatterns(fieldBindingVarAssignmentListNode); return SourceModel.Expr.Case.Alt.UnpackRecord.make(baseRecordPattern, fieldPatterns, altExpr); } default: { throw new IllegalStateException("Unexpected parse tree node " + fullPatternNode.toDebugString() + "."); } } } static SourceModel.Expr.Case buildCaseExpr(ParseTreeNode caseExprNode) { caseExprNode.verifyType(CALTreeParserTokenTypes.LITERAL_case); ParseTreeNode conditionExprNode = caseExprNode.firstChild(); ParseTreeNode altListNode = conditionExprNode.nextSibling(); altListNode.verifyType(CALTreeParserTokenTypes.ALT_LIST); final int nAlts = altListNode.getNumberOfChildren(); SourceModel.Expr.Case.Alt[] caseAlts = new SourceModel.Expr.Case.Alt[nAlts]; int i = 0; for (final ParseTreeNode altNode : altListNode) { caseAlts[i] = buildCaseAlt(altNode); ++i; } return SourceModel.Expr.Case.makeAnnotated(buildExpr(conditionExprNode), caseAlts, caseExprNode.getAssemblySourceRange()); } static SourceModel.Expr.If buildIfExpr(ParseTreeNode ifExprNode) { return SourceModel.Expr.If.makeAnnotated(buildExpr(ifExprNode.firstChild()), buildExpr(ifExprNode.getChild(1)), buildExpr(ifExprNode.getChild(2)), ifExprNode.getAssemblySourceRange()); } static SourceModel.Expr.BinaryOp.Or buildOrExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.BARBAR); return SourceModel.Expr.BinaryOp.Or.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.And buildAndExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.AMPERSANDAMPERSAND); return SourceModel.Expr.BinaryOp.And.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.Append buildAppendExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.PLUSPLUS); return SourceModel.Expr.BinaryOp.Append.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.LessThan buildLessThanExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.LESS_THAN); return SourceModel.Expr.BinaryOp.LessThan.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.LessThanEquals buildLessThanEqualsExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.LESS_THAN_OR_EQUALS); return SourceModel.Expr.BinaryOp.LessThanEquals.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.Equals buildEqualsExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.EQUALSEQUALS); return SourceModel.Expr.BinaryOp.Equals.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.NotEquals buildNotEqualsExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.NOT_EQUALS); return SourceModel.Expr.BinaryOp.NotEquals.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.GreaterThanEquals buildGreaterThanEqualsExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.GREATER_THAN_OR_EQUALS); return SourceModel.Expr.BinaryOp.GreaterThanEquals.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.GreaterThan buildGreaterThanExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.GREATER_THAN); return SourceModel.Expr.BinaryOp.GreaterThan.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.Add buildAddExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.PLUS); return SourceModel.Expr.BinaryOp.Add.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.Subtract buildSubtractExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.MINUS); return SourceModel.Expr.BinaryOp.Subtract.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.Multiply buildMultiplyExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.ASTERISK); return SourceModel.Expr.BinaryOp.Multiply.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.Divide buildDivideExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.SOLIDUS); return SourceModel.Expr.BinaryOp.Divide.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.Remainder buildRemainderExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.PERCENT); return SourceModel.Expr.BinaryOp.Remainder.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.Compose buildComposeExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.POUND); return SourceModel.Expr.BinaryOp.Compose.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.Apply buildApplyExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.DOLLAR); return SourceModel.Expr.BinaryOp.Apply.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.Cons buildConsExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.COLON); return SourceModel.Expr.BinaryOp.Cons.makeAnnotated(buildExpr(exprNode.firstChild()), buildExpr(exprNode.getChild(1)), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.UnaryOp.Negate buildNegateExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.UNARY_MINUS); return SourceModel.Expr.UnaryOp.Negate.makeAnnotated(buildExpr(exprNode.firstChild()), exprNode.getAssemblySourceRange(), exprNode.getSourceRange()); } static SourceModel.Expr.BinaryOp.BackquotedOperator buildBackquotedOperatorExpr(ParseTreeNode exprNode) { exprNode.verifyType(CALTreeParserTokenTypes.BACKQUOTE); ParseTreeNode applicationNode = exprNode.getChild(0); ParseTreeNode qualifiedNameNode = applicationNode.getChild(0); qualifiedNameNode.verifyType(CALTreeParserTokenTypes.QUALIFIED_VAR, CALTreeParserTokenTypes.QUALIFIED_CONS); // Two cases: this is a function name being or this is a data constructor being backquoted. if (qualifiedNameNode.getType() == CALTreeParserTokenTypes.QUALIFIED_VAR){ // function name return SourceModel.Expr.BinaryOp.BackquotedOperator.Var.makeAnnotated( buildVarExpr(qualifiedNameNode), buildExpr(applicationNode.getChild(1)), buildExpr(applicationNode.getChild(2)), exprNode.getAssemblySourceRange(), qualifiedNameNode.getAssemblySourceRange() ); } else{ // data constructor return SourceModel.Expr.BinaryOp.BackquotedOperator.DataCons.makeAnnotated( buildDataConsExpr(qualifiedNameNode), buildExpr(applicationNode.getChild(1)), buildExpr(applicationNode.getChild(2)), exprNode.getAssemblySourceRange(), qualifiedNameNode.getAssemblySourceRange() ); } } static SourceModel.Expr.Application buildApplicationExpr(ParseTreeNode applicationExprNode) { applicationExprNode.verifyType(CALTreeParserTokenTypes.APPLICATION); int nChildren = applicationExprNode.getNumberOfChildren(); if (nChildren < 2) { throw new IllegalArgumentException("an application must involve 2 or more expressions."); } int exprN = 0; SourceModel.Expr[] expressions = new SourceModel.Expr[nChildren]; for (final ParseTreeNode exprNode : applicationExprNode) { expressions[exprN] = buildExpr(exprNode); ++exprN; } return SourceModel.Expr.Application.makeAnnotated(expressions, applicationExprNode.getAssemblySourceRange()); } static SourceModel.Expr.DataCons buildDataConsExpr(ParseTreeNode qualifiedConsNode) { qualifiedConsNode.verifyType(CALTreeParserTokenTypes.QUALIFIED_CONS); SourceModel.Name.DataCons dataConsName = buildDataConsName(qualifiedConsNode); return SourceModel.Expr.DataCons.makeAnnotated(dataConsName, dataConsName.getSourceRange()); } static SourceModel.Expr.Var buildVarExpr(ParseTreeNode qualifiedVarNode) { qualifiedVarNode.verifyType(CALTreeParserTokenTypes.QUALIFIED_VAR); SourceModel.Name.Function varName = buildFunctionName(qualifiedVarNode); return SourceModel.Expr.Var.makeAnnotated(varName, varName.getSourceRange()); } static SourceModel.Expr.Literal.Num buildNumLiteralExpr(ParseTreeNode numLiteralNode) { numLiteralNode.verifyType(CALTreeParserTokenTypes.INTEGER_LITERAL); //may throw a NumberFormatException if unsuccessful in parsing the value. This should //never happen from nodes created by the parser. BigInteger value = new BigInteger(numLiteralNode.getText()); return SourceModel.Expr.Literal.Num.makeAnnotated(value, numLiteralNode.getAssemblySourceRange()); } static SourceModel.Expr.Literal.Double buildDoubleLiteralExpr(ParseTreeNode doubleLiteralNode) { doubleLiteralNode.verifyType(CALTreeParserTokenTypes.FLOAT_LITERAL); //may throw a NumberFormatException if unsuccessful in parsing the value. This should //never happen from nodes created by the parser. Double value = new Double(doubleLiteralNode.getText()); return SourceModel.Expr.Literal.Double.makeAnnotated(value.doubleValue(), doubleLiteralNode.getAssemblySourceRange()); } static SourceModel.Expr.Literal.Char buildCharLiteralExpr(ParseTreeNode charLiteralNode) { char c = StringEncoder.unencodeChar(charLiteralNode.getText()); return SourceModel.Expr.Literal.Char.makeAnnotated(c, charLiteralNode.getSourceRange()); } static SourceModel.Expr.Literal.StringLit buildStringLiteralExpr(ParseTreeNode stringLiteralNode) { String unencodedString = StringEncoder.unencodeString(stringLiteralNode.getText()); return SourceModel.Expr.Literal.StringLit.makeAnnotated(unencodedString, stringLiteralNode.getAssemblySourceRange()); } static SourceModel.Expr.Unit buildUnitExpr(ParseTreeNode unitNode) { return SourceModel.Expr.Unit.makeAnnotated(unitNode.getAssemblySourceRange()); } static SourceModel.Expr.Tuple buildTupleExpr(ParseTreeNode tupleNode) { tupleNode.verifyType(CALTreeParserTokenTypes.TUPLE_CONSTRUCTOR); int size = tupleNode.getNumberOfChildren(); if (size < 2) { throw new IllegalArgumentException("must have 2 or more components in a tuple."); } SourceModel.Expr[] components = new SourceModel.Expr[size]; int i = 0; for (final ParseTreeNode componentNode : tupleNode) { components[i] = buildExpr(componentNode); ++i; } return SourceModel.Expr.Tuple.makeAnnotated(components, tupleNode.getAssemblySourceRange()); } static SourceModel.Expr.List buildListExpr(ParseTreeNode listNode) { listNode.verifyType(CALTreeParserTokenTypes.LIST_CONSTRUCTOR); int nElements = listNode.getNumberOfChildren(); SourceModel.Expr[] elements = new SourceModel.Expr[nElements]; int i = 0; for (final ParseTreeNode elementNode : listNode) { elements[i] = buildExpr(elementNode); ++i; } return SourceModel.Expr.List.makeAnnotated(elements, listNode.getAssemblySourceRange()); } static SourceModel.Expr.Record buildRecordExpr(ParseTreeNode recordExprNode) { recordExprNode.verifyType(CALTreeParserTokenTypes.RECORD_CONSTRUCTOR); ParseTreeNode baseRecordNode = recordExprNode.firstChild(); baseRecordNode.verifyType(CALTreeParserTokenTypes.BASE_RECORD); ParseTreeNode baseRecordExprNode = baseRecordNode.firstChild(); SourceModel.Expr baseRecordExpr = null; if (baseRecordExprNode != null) { baseRecordExpr = buildExpr(baseRecordExprNode); } ParseTreeNode fieldModificationListNode = baseRecordNode.nextSibling(); fieldModificationListNode.verifyType(CALTreeParserTokenTypes.FIELD_MODIFICATION_LIST); final int nFieldValuePairs = fieldModificationListNode.getNumberOfChildren(); int i = 0; SourceModel.Expr.Record.FieldModification[] fieldValuePairs = new SourceModel.Expr.Record.FieldModification[nFieldValuePairs]; for (final ParseTreeNode fieldModificationNode : fieldModificationListNode) { fieldModificationNode.verifyType(CALTreeParserTokenTypes.FIELD_EXTENSION, CALTreeParserTokenTypes.FIELD_VALUE_UPDATE); ParseTreeNode fieldNameNode = fieldModificationNode.firstChild(); SourceModel.Name.Field fieldName = buildFieldName(fieldNameNode); ParseTreeNode assignmentNode = fieldNameNode.nextSibling(); SourceModel.Expr assignmentExpr = buildExpr(assignmentNode); switch (fieldModificationNode.getType()) { case CALTreeParserTokenTypes.FIELD_EXTENSION: fieldValuePairs[i] = SourceModel.Expr.Record.FieldModification.Extension.make(fieldName, assignmentExpr); break; case CALTreeParserTokenTypes.FIELD_VALUE_UPDATE: fieldValuePairs[i] = SourceModel.Expr.Record.FieldModification.Update.make(fieldName, assignmentExpr); break; default: throw new IllegalStateException("Unexpected parse tree node " + fieldModificationNode.toDebugString() + "."); } ++i; } return SourceModel.Expr.Record.make(baseRecordExpr, fieldValuePairs); } static SourceModel.Expr.SelectRecordField buildSelectRecordFieldExpr(ParseTreeNode selectRecordFieldNode) { selectRecordFieldNode.verifyType(CALTreeParserTokenTypes.SELECT_RECORD_FIELD); ParseTreeNode exprNode = selectRecordFieldNode.firstChild(); ParseTreeNode fieldNameNode = exprNode.nextSibling(); SourceModel.Name.Field fieldName = buildFieldName(fieldNameNode); return SourceModel.Expr.SelectRecordField.make(buildExpr(exprNode), fieldName); } static SourceModel.Expr.SelectDataConsField buildSelectDataConsFieldExpr(ParseTreeNode selectDataConsFieldNode) { selectDataConsFieldNode.verifyType(CALTreeParserTokenTypes.SELECT_DATA_CONSTRUCTOR_FIELD); ParseTreeNode exprNode = selectDataConsFieldNode.firstChild(); ParseTreeNode qualifiedConsNode = exprNode.nextSibling(); ParseTreeNode fieldNameNode = qualifiedConsNode.nextSibling(); SourceModel.Name.Field fieldName = buildFieldName(fieldNameNode); return SourceModel.Expr.SelectDataConsField.makeAnnotated(buildExpr(exprNode), buildDataConsName(qualifiedConsNode), fieldName, qualifiedConsNode.getAssemblySourceRange()); } static SourceModel.Expr.ExprTypeSignature buildExprTypeSignature(ParseTreeNode exprTypeSignatureNode) { exprTypeSignatureNode.verifyType(CALTreeParserTokenTypes.EXPRESSION_TYPE_SIGNATURE); ParseTreeNode exprNode = exprTypeSignatureNode.firstChild(); ParseTreeNode signatureNode = exprNode.nextSibling(); return SourceModel.Expr.ExprTypeSignature.make(buildExpr(exprNode), buildTypeSignature(signatureNode)); } static SourceModel.Expr buildParenExpr(ParseTreeNode parseTree) { return SourceModel.Expr.Parenthesized.makeAnnotated(buildExpr(parseTree.firstChild()), parseTree.getSourceRange()); } static SourceModel.Expr buildExpr(ParseTreeNode parseTree) { switch (parseTree.getType()) { case CALTreeParserTokenTypes.LITERAL_let : return buildLetExpr(parseTree); case CALTreeParserTokenTypes.LAMBDA_DEFN : return buildLambdaExpr(parseTree); case CALTreeParserTokenTypes.LITERAL_case : return buildCaseExpr(parseTree); case CALTreeParserTokenTypes.LITERAL_if : return buildIfExpr(parseTree); case CALTreeParserTokenTypes.BARBAR : return buildOrExpr(parseTree); case CALTreeParserTokenTypes.AMPERSANDAMPERSAND : return buildAndExpr(parseTree); case CALTreeParserTokenTypes.PLUSPLUS : return buildAppendExpr(parseTree); case CALTreeParserTokenTypes.LESS_THAN : return buildLessThanExpr(parseTree); case CALTreeParserTokenTypes.LESS_THAN_OR_EQUALS : return buildLessThanEqualsExpr(parseTree); case CALTreeParserTokenTypes.EQUALSEQUALS : return buildEqualsExpr(parseTree); case CALTreeParserTokenTypes.NOT_EQUALS : return buildNotEqualsExpr(parseTree); case CALTreeParserTokenTypes.GREATER_THAN_OR_EQUALS : return buildGreaterThanEqualsExpr(parseTree); case CALTreeParserTokenTypes.GREATER_THAN : return buildGreaterThanExpr(parseTree); case CALTreeParserTokenTypes.PLUS : return buildAddExpr(parseTree); case CALTreeParserTokenTypes.MINUS : return buildSubtractExpr(parseTree); case CALTreeParserTokenTypes.ASTERISK : return buildMultiplyExpr(parseTree); case CALTreeParserTokenTypes.SOLIDUS : return buildDivideExpr(parseTree); case CALTreeParserTokenTypes.PERCENT: return buildRemainderExpr(parseTree); case CALTreeParserTokenTypes.COLON : return buildConsExpr(parseTree); case CALTreeParserTokenTypes.UNARY_MINUS: return buildNegateExpr(parseTree); case CALTreeParserTokenTypes.POUND: return buildComposeExpr(parseTree); case CALTreeParserTokenTypes.DOLLAR: return buildApplyExpr(parseTree); case CALTreeParserTokenTypes.BACKQUOTE: return buildBackquotedOperatorExpr(parseTree); case CALTreeParserTokenTypes.APPLICATION : { ParseTreeNode exprNode = parseTree.firstChild(); if (exprNode.nextSibling() == null) { //there are some "artificial" application nodes with only 1 child. return buildExpr(exprNode); } return buildApplicationExpr(parseTree); } case CALTreeParserTokenTypes.QUALIFIED_VAR : return buildVarExpr(parseTree); case CALTreeParserTokenTypes.QUALIFIED_CONS : return buildDataConsExpr(parseTree); case CALTreeParserTokenTypes.INTEGER_LITERAL : return buildNumLiteralExpr(parseTree); case CALTreeParserTokenTypes.FLOAT_LITERAL : return buildDoubleLiteralExpr(parseTree); case CALTreeParserTokenTypes.CHAR_LITERAL: return buildCharLiteralExpr(parseTree); case CALTreeParserTokenTypes.STRING_LITERAL: return buildStringLiteralExpr(parseTree); //A parenthesized expression, a tuple or the trivial type case CALTreeParserTokenTypes.TUPLE_CONSTRUCTOR : { if (parseTree.hasNoChildren()) { return buildUnitExpr(parseTree); } if (parseTree.hasExactlyOneChild()) { //a parenthesized expression return buildParenExpr(parseTree); } return buildTupleExpr(parseTree); } //A list data value case CALTreeParserTokenTypes.LIST_CONSTRUCTOR : return buildListExpr(parseTree); case CALTreeParserTokenTypes.RECORD_CONSTRUCTOR: return buildRecordExpr(parseTree); case CALTreeParserTokenTypes.SELECT_RECORD_FIELD: return buildSelectRecordFieldExpr(parseTree); case CALTreeParserTokenTypes.SELECT_DATA_CONSTRUCTOR_FIELD: return buildSelectDataConsFieldExpr(parseTree); case CALTreeParserTokenTypes.EXPRESSION_TYPE_SIGNATURE: return buildExprTypeSignature(parseTree); default : { throw new IllegalStateException("Unexpected parse tree node " + parseTree.toDebugString() + "."); } } } static SourceModel.TypeExprDefn.Function buildFunctionTypeDefn(ParseTreeNode functionTypeDefnNode) { functionTypeDefnNode.verifyType(CALTreeParserTokenTypes.FUNCTION_TYPE_CONSTRUCTOR); return SourceModel.TypeExprDefn.Function.makeAnnotated(buildTypeExprDefn(functionTypeDefnNode.firstChild()), buildTypeExprDefn(functionTypeDefnNode.getChild(1)), functionTypeDefnNode.getAssemblySourceRange(), functionTypeDefnNode.getSourceRange()); } static SourceModel.TypeExprDefn.Tuple buildTupleTypeDefn(ParseTreeNode tupleTypeDefnNode) { tupleTypeDefnNode.verifyType(CALTreeParserTokenTypes.TUPLE_TYPE_CONSTRUCTOR); int nChildren = tupleTypeDefnNode.getNumberOfChildren(); if (nChildren < 2) { throw new IllegalArgumentException("must have 2 or more components in a tuple type."); } SourceModel.TypeExprDefn[] components = new SourceModel.TypeExprDefn[nChildren]; int i = 0; for (final ParseTreeNode componentNode : tupleTypeDefnNode) { components[i] = buildTypeExprDefn(componentNode); ++i; } return SourceModel.TypeExprDefn.Tuple.makeAnnotated(components, tupleTypeDefnNode.getAssemblySourceRange()); } static SourceModel.TypeExprDefn.List buildListTypeExprDefn(ParseTreeNode listTypeNode) { listTypeNode.verifyType(CALTreeParserTokenTypes.LIST_TYPE_CONSTRUCTOR); ParseTreeNode elementNode = listTypeNode.firstChild(); SourceModel.TypeExprDefn element = buildTypeExprDefn(elementNode); return SourceModel.TypeExprDefn.List.makeAnnotated(element, listTypeNode.getAssemblySourceRange()); } static SourceModel.TypeExprDefn.Application buildApplicationTypeExprDefn(ParseTreeNode applicationTypeNode) { applicationTypeNode.verifyType(CALTreeParserTokenTypes. TYPE_APPLICATION); int nChildren = applicationTypeNode.getNumberOfChildren(); if (nChildren < 2) { throw new IllegalArgumentException("a type application must involve 2 or more type expressions."); } int exprN = 0; SourceModel.TypeExprDefn[] expressions = new SourceModel.TypeExprDefn[nChildren]; for (final ParseTreeNode exprNode : applicationTypeNode) { expressions[exprN] = buildTypeExprDefn(exprNode); ++exprN; } return SourceModel.TypeExprDefn.Application.makeAnnotated(expressions, applicationTypeNode.getAssemblySourceRange()); } static SourceModel.TypeExprDefn.TypeCons buildTypeCons(ParseTreeNode qualifiedTypeConsNameNode) { qualifiedTypeConsNameNode.verifyType(CALTreeParserTokenTypes.QUALIFIED_CONS); SourceModel.Name.TypeCons typeConsName = buildTypeConsName(qualifiedTypeConsNameNode); return SourceModel.TypeExprDefn.TypeCons.makeAnnotated(typeConsName, qualifiedTypeConsNameNode.getAssemblySourceRange()); } /** * Builds a source model representation of a type variable name from the given ParseTreeNode. * @param typeVarNameNode the ParseTreeNode representing a type variable name. * @return a source model representation of the type variable name. */ static SourceModel.Name.TypeVar buildTypeVarName(ParseTreeNode typeVarNameNode) { typeVarNameNode.verifyType(CALTreeParserTokenTypes.VAR_ID); return SourceModel.Name.TypeVar.makeAnnotated(typeVarNameNode.getText(), typeVarNameNode.getAssemblySourceRange()); } static SourceModel.TypeExprDefn.TypeVar buildTypeVar(ParseTreeNode typeVarNameNode) { typeVarNameNode.verifyType(CALTreeParserTokenTypes.VAR_ID); return SourceModel.TypeExprDefn.TypeVar.makeAnnotated(buildTypeVarName(typeVarNameNode), typeVarNameNode.getAssemblySourceRange()); } static SourceModel.TypeExprDefn.Record buildRecordTypeExprDefn(ParseTreeNode recordTypeNode) { recordTypeNode.verifyType(CALTreeParserTokenTypes.RECORD_TYPE_CONSTRUCTOR); ParseTreeNode recordVarNode = recordTypeNode.firstChild(); recordVarNode.verifyType(CALTreeParserTokenTypes.RECORD_VAR); ParseTreeNode recordVarNameNode = recordVarNode.firstChild(); SourceModel.TypeExprDefn.TypeVar recordVarName = null; if (recordVarNameNode != null) { recordVarName = buildTypeVar(recordVarNameNode); } ParseTreeNode fieldTypeAssignmentListNode = recordVarNode.nextSibling(); fieldTypeAssignmentListNode.verifyType(CALTreeParserTokenTypes.FIELD_TYPE_ASSIGNMENT_LIST); final int nFieldTypePairs = fieldTypeAssignmentListNode.getNumberOfChildren(); int i = 0; SourceModel.TypeExprDefn.Record.FieldTypePair[] fieldTypePairs = new SourceModel.TypeExprDefn.Record.FieldTypePair[nFieldTypePairs]; for (final ParseTreeNode fieldTypeAssignmentNode : fieldTypeAssignmentListNode) { fieldTypeAssignmentNode.verifyType(CALTreeParserTokenTypes.FIELD_TYPE_ASSIGNMENT); ParseTreeNode fieldNameNode = fieldTypeAssignmentNode.firstChild(); SourceModel.Name.Field fieldName = buildFieldName(fieldNameNode); ParseTreeNode typeNode = fieldNameNode.nextSibling(); SourceModel.TypeExprDefn typeExprDefn = buildTypeExprDefn(typeNode); fieldTypePairs[i] = SourceModel.TypeExprDefn.Record.FieldTypePair.make(fieldName, typeExprDefn); ++i; } return SourceModel.TypeExprDefn.Record.makeAnnotated(recordVarName, fieldTypePairs, recordTypeNode.getAssemblySourceRange()); } static SourceModel.TypeExprDefn buildParenthesizedTypeExprDefn(ParseTreeNode parseTree) { return SourceModel.TypeExprDefn.Parenthesized.makeAnnotated(buildTypeExprDefn(parseTree.firstChild()), parseTree.getSourceRange()); } static SourceModel.TypeExprDefn buildTypeExprDefn(ParseTreeNode parseTree) { switch (parseTree.getType()) { case CALTreeParserTokenTypes.FUNCTION_TYPE_CONSTRUCTOR : return buildFunctionTypeDefn(parseTree); case CALTreeParserTokenTypes.TUPLE_TYPE_CONSTRUCTOR : { if (parseTree.hasNoChildren()) { return SourceModel.TypeExprDefn.Unit.makeAnnotated(parseTree.getAssemblySourceRange()); } if (parseTree.hasExactlyOneChild()) { // the type (t) is equivalent to the type t. return buildParenthesizedTypeExprDefn(parseTree); } return buildTupleTypeDefn(parseTree); } case CALTreeParserTokenTypes.LIST_TYPE_CONSTRUCTOR : return buildListTypeExprDefn(parseTree); case CALTreeParserTokenTypes.TYPE_APPLICATION : { if (parseTree.hasExactlyOneChild()) { //not really an application node, but an artifact of parsing return buildTypeExprDefn(parseTree.firstChild()); } return buildApplicationTypeExprDefn(parseTree); } case CALTreeParserTokenTypes.QUALIFIED_CONS : return buildTypeCons(parseTree); case CALTreeParserTokenTypes.VAR_ID : return buildTypeVar(parseTree); case CALTreeParserTokenTypes.RECORD_TYPE_CONSTRUCTOR : return buildRecordTypeExprDefn(parseTree); default : { throw new IllegalStateException("Unexpected parse tree node " + parseTree.toDebugString() + "."); } } } /** * Builds a source model representation of a module name in CAL source. * Returns null if the given node is the empty module name qualifier. * * @param maybeEmptyModuleNameNode the root of the parse tree representing a module name or an empty module name qualifier. * @return a source model representation of a module name in CAL source, or null if the given node is the empty module name qualifier. */ static SourceModel.Name.Module buildMaybeEmptyModuleName(ParseTreeNode maybeEmptyModuleNameNode) { maybeEmptyModuleNameNode.verifyType(CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME, CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME_EMPTY_QUALIFIER); if (maybeEmptyModuleNameNode.getType() == CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME_EMPTY_QUALIFIER) { return null; } else { return buildModuleName(maybeEmptyModuleNameNode); } } /** * Builds a source model representation of a module name in CAL source. * @param moduleNameNode the root of the parse tree representing a module name. * @return a source model representation of a module name in CAL source. */ static SourceModel.Name.Module buildModuleName(ParseTreeNode moduleNameNode) { moduleNameNode.verifyType(CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME); ParseTreeNode qualifierNode = moduleNameNode.firstChild(); SourceModel.Name.Module.Qualifier qualifier = buildModuleNameQualifier(qualifierNode); ParseTreeNode unqualifiedModuleNameNode = qualifierNode.nextSibling(); unqualifiedModuleNameNode.verifyType(CALTreeParserTokenTypes.CONS_ID); String unqualifiedModuleName = unqualifiedModuleNameNode.getText(); return SourceModel.Name.Module.makeAnnotated(qualifier, unqualifiedModuleName, moduleNameNode.getAssemblySourceRange()); } /** * Builds a source model representation of a module name qualifier. * @param qualifierNode the root of the parse tree representing a module name qualifier. * @return a source model representation of a module name qualifier. */ static SourceModel.Name.Module.Qualifier buildModuleNameQualifier(final ParseTreeNode qualifierNode) { qualifierNode.verifyType(CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME, CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME_EMPTY_QUALIFIER); List/*String*/<String> components = new ArrayList<String>(); ParseTreeNode currentQualifierNode = qualifierNode; // loop through the qualifier tree, extracting components in reverse order // e.g. for a qualifier A.B.C, the loop will go through the components in the order: C, B, A while (currentQualifierNode.getType() == CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME) { ParseTreeNode parentQualifierNode = currentQualifierNode.firstChild(); parentQualifierNode.verifyType(CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME, CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME_EMPTY_QUALIFIER); ParseTreeNode trailingComponentNode = parentQualifierNode.nextSibling(); trailingComponentNode.verifyType(CALTreeParserTokenTypes.CONS_ID); String trailingComponent = trailingComponentNode.getText(); // add the trailing component to the front (ahead of the components already added) // so that for the qualifier A.B.C and trailing component A, A will be added ahead of the list [B, C] components.add(0, trailingComponent); currentQualifierNode = parentQualifierNode; } // we should've reached the end of the chain - i.e. a HIERARCHICAL_MODULE_NAME_EMPTY_QUALIFIER currentQualifierNode.verifyType(CALTreeParserTokenTypes.HIERARCHICAL_MODULE_NAME_EMPTY_QUALIFIER); return SourceModel.Name.Module.Qualifier.makeAnnotated( components.toArray(new String[components.size()]), qualifierNode.getAssemblySourceRange()); } static SourceModel.Name.TypeClass buildTypeClassName(ParseTreeNode typeClassNameNode) { typeClassNameNode.verifyType(CALTreeParserTokenTypes.QUALIFIED_CONS); ParseTreeNode moduleNameNode = typeClassNameNode.firstChild(); SourceModel.Name.Module moduleName = buildMaybeEmptyModuleName(moduleNameNode); ParseTreeNode classNameNode = moduleNameNode.nextSibling(); return SourceModel.Name.TypeClass.makeAnnotated(moduleName, classNameNode.getText(), typeClassNameNode.getAssemblySourceRange()); } static SourceModel.Name.TypeCons buildTypeConsName(ParseTreeNode qualifiedConsNode) { qualifiedConsNode.verifyType(CALTreeParserTokenTypes.QUALIFIED_CONS); ParseTreeNode moduleNameNode = qualifiedConsNode.firstChild(); SourceModel.Name.Module moduleName = buildMaybeEmptyModuleName(moduleNameNode); ParseTreeNode consNameNode = moduleNameNode.nextSibling(); return SourceModel.Name.TypeCons.makeAnnotated(moduleName, consNameNode.getText(), qualifiedConsNode.getAssemblySourceRange()); } static SourceModel.Name.Function buildFunctionName(ParseTreeNode qualifiedFunctionNode) { qualifiedFunctionNode.verifyType(CALTreeParserTokenTypes.QUALIFIED_VAR); ParseTreeNode moduleNameNode = qualifiedFunctionNode.firstChild(); SourceModel.Name.Module moduleName = buildMaybeEmptyModuleName(moduleNameNode); ParseTreeNode functionNameNode = moduleNameNode.nextSibling(); return SourceModel.Name.Function.makeAnnotated(moduleName, functionNameNode.getText(), qualifiedFunctionNode.getAssemblySourceRange(), functionNameNode.getSourceRange()); } static SourceModel.Name.DataCons buildDataConsName(ParseTreeNode qualifiedConsNode) { qualifiedConsNode.verifyType(CALTreeParserTokenTypes.QUALIFIED_CONS); ParseTreeNode moduleNameNode = qualifiedConsNode.firstChild(); SourceModel.Name.Module moduleName = buildMaybeEmptyModuleName(moduleNameNode); ParseTreeNode consNameNode = moduleNameNode.nextSibling(); return SourceModel.Name.DataCons.makeAnnotated(moduleName, consNameNode.getText(), qualifiedConsNode.getAssemblySourceRange()); } /** * Builds a source model representation of a CALDoc text block from the given ParseTreeNode. * @param blockNode the ParseTreeNode representing a CALDoc text block. * @return a source model representation of the CALDoc text block. */ static SourceModel.CALDoc.TextBlock buildCALDocTextBlock(ParseTreeNode blockNode) { blockNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT); return SourceModel.CALDoc.TextBlock.make(buildCALDocTopLevelTextSegments(blockNode)); } /** * Builds a source model representation of a preformatted text segment in a CALDoc comment from the given ParseTreeNode. * @param blockNode the ParseTreeNode representing a CALDoc preformatted text segment. * @return a source model representation of a preformatted text segment in a CALDoc comment. */ static SourceModel.CALDoc.TextSegment.Preformatted buildCALDocPreformattedBlock(ParseTreeNode blockNode) { blockNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_PREFORMATTED_BLOCK); return SourceModel.CALDoc.TextSegment.Preformatted.make(buildCALDocTopLevelTextSegments(blockNode)); } /** * Creates a source model representation of a CALDoc plain text segment from a string builder holding onto a piece of * escaped text. * @param plainSegmentBuffer the string builder holding onto a piece of escaped text. * @return a source model representation of a CALDoc plain text segment. */ private static SourceModel.CALDoc.TextSegment.Plain makeUnescapedCALDocPlainTextSegment(StringBuilder plainSegmentBuffer) { String text = plainSegmentBuffer.toString(); text = text.replaceAll("\\\\\\{@", "{@"); // '\{@' -> '{@' text = text.replaceAll("\\\\@", "@"); // '\@' -> '@' return SourceModel.CALDoc.TextSegment.Plain.make(text); } /** * Builds a source model representation of a CALDoc plain text segment from the given ParseTreeNode of the type * CALDOC_TEXT_BLOCK_WITHOUT_INLINE_TAGS. * * @param blockNode the ParseTreeNode representing a CALDOC_TEXT_BLOCK_WITHOUT_INLINE_TAGS. * @return a source model representation of a CALDoc plain text segment. */ static SourceModel.CALDoc.TextSegment.Plain buildCALDocTextBlockWithoutInlineTags(ParseTreeNode blockNode) { blockNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_BLOCK_WITHOUT_INLINE_TAGS); StringBuilder plainSegmentBuffer = new StringBuilder(); for (final ParseTreeNode contentNode : blockNode) { switch (contentNode.getType()) { case CALTreeParserTokenTypes.CALDOC_TEXT_LINE: case CALTreeParserTokenTypes.CALDOC_BLANK_TEXT_LINE: { String text = contentNode.getText(); plainSegmentBuffer.append(text); break; } case CALTreeParserTokenTypes.CALDOC_TEXT_LINE_BREAK: { plainSegmentBuffer.append('\n'); break; } default: throw new IllegalStateException("Unexpected parse tree node " + contentNode.toDebugString() + "."); } } return makeUnescapedCALDocPlainTextSegment(plainSegmentBuffer); } /** * Builds an array of SourceModel.CALDoc.TextSegment.TopLevel objects representing the text segments that are the children * of the supplied ParseTreeNode. * * @param parentNodeOfSegments the ParseTreeNode whose children represent text segments in a CALDoc comment. * @return an array of SourceModel.CALDoc.TextSegment.TopLevel objects representing the text segments. */ private static SourceModel.CALDoc.TextSegment.TopLevel[] buildCALDocTopLevelTextSegments(ParseTreeNode parentNodeOfSegments) { /// We keep a list of the segments that are built as we loop through the children nodes. // List<TopLevel> segments = new ArrayList<TopLevel>(); //// /// A plain text segment is represented as one or more of CALDOC_TEXT_LINE, CALDOC_BLANK_TEXT_LINE and /// CALDOC_TEXT_LINE_BREAK. We loop through the children of the supplied node aggregating contiguous blocks /// of these nodes into plain text segments. A CALDOC_TEXT_INLINE_BLOCK node represents an inline block and is /// handled as an independent segment. // StringBuilder plainSegmentBuffer = new StringBuilder(); for (final ParseTreeNode contentNode : parentNodeOfSegments) { switch (contentNode.getType()) { case CALTreeParserTokenTypes.CALDOC_TEXT_LINE: case CALTreeParserTokenTypes.CALDOC_BLANK_TEXT_LINE: { String text = contentNode.getText(); plainSegmentBuffer.append(text); break; } case CALTreeParserTokenTypes.CALDOC_TEXT_LINE_BREAK: { plainSegmentBuffer.append('\n'); break; } case CALTreeParserTokenTypes.CALDOC_TEXT_INLINE_BLOCK: { // process the buffered up plain text first if (plainSegmentBuffer.length() > 0) { // convert the plain text buffer into a segment and add it to the list SourceModel.CALDoc.TextSegment.Plain plainTextSegment = makeUnescapedCALDocPlainTextSegment(plainSegmentBuffer); segments.add(plainTextSegment); // reset the buffer afterwards for future use plainSegmentBuffer = new StringBuilder(); } // then process the inline tag segment SourceModel.CALDoc.TextSegment.InlineTag inlineTagSegment = buildCALDocInlineTagSegment(contentNode); segments.add(inlineTagSegment); break; } default: throw new IllegalStateException("Unexpected parse tree node " + contentNode.toDebugString() + "."); } } // one final flush of the plain text buffer into a segment if (plainSegmentBuffer.length() > 0) { SourceModel.CALDoc.TextSegment.Plain plainTextSegment = makeUnescapedCALDocPlainTextSegment(plainSegmentBuffer); segments.add(plainTextSegment); } /// create the array of source model segments from the list we've been building up. // return segments.toArray(SourceModel.CALDoc.TextSegment.TopLevel.NO_SEGMENTS); } /** * Builds a source model representation of an inline tag segment in a CALDoc comment from the given ParseTreeNode. * @param inlineBlockNode the ParseTreeNode representing an inline tag segment in a CALDoc comment. * @return a source model representation of an inline tag segment in a CALDoc comment. */ static SourceModel.CALDoc.TextSegment.InlineTag buildCALDocInlineTagSegment(ParseTreeNode inlineBlockNode) { inlineBlockNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_INLINE_BLOCK); ParseTreeNode inlineTagNode = inlineBlockNode.firstChild(); switch (inlineTagNode.getType()) { case CALTreeParserTokenTypes.CALDOC_TEXT_URL: return buildCALDocInlineURLTagSegment(inlineTagNode); case CALTreeParserTokenTypes.CALDOC_TEXT_LINK: return buildCALDocInlineLinkTagSegment(inlineTagNode); case CALTreeParserTokenTypes.CALDOC_TEXT_EMPHASIZED_TEXT: return buildCALDocInlineEmTagSegment(inlineTagNode); case CALTreeParserTokenTypes.CALDOC_TEXT_STRONGLY_EMPHASIZED_TEXT: return buildCALDocInlineStrongTagSegment(inlineTagNode); case CALTreeParserTokenTypes.CALDOC_TEXT_SUPERSCRIPT_TEXT: return buildCALDocInlineSupTagSegment(inlineTagNode); case CALTreeParserTokenTypes.CALDOC_TEXT_SUBSCRIPT_TEXT: return buildCALDocInlineSubTagSegment(inlineTagNode); case CALTreeParserTokenTypes.CALDOC_TEXT_SUMMARY: return buildCALDocInlineSummaryTagSegment(inlineTagNode); case CALTreeParserTokenTypes.CALDOC_TEXT_CODE_BLOCK: return buildCALDocInlineCodeTagSegment(inlineTagNode); case CALTreeParserTokenTypes.CALDOC_TEXT_ORDERED_LIST: return buildCALDocInlineListTagSegment(inlineTagNode); case CALTreeParserTokenTypes.CALDOC_TEXT_UNORDERED_LIST: return buildCALDocInlineListTagSegment(inlineTagNode); default: throw new IllegalStateException("Unexpected parse tree node " + inlineTagNode.toDebugString() + "."); } } /** * Builds a source model representation of a hyperlinkable URL in a CALDoc comment from the given ParseTreeNode. * @param urlNode the ParseTreeNode representing a hyperlinkable URL in a CALDoc comment. * @return a source model representation of a hyperlinkable URL in a CALDoc comment. */ static SourceModel.CALDoc.TextSegment.InlineTag.URL buildCALDocInlineURLTagSegment(ParseTreeNode urlNode) { urlNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_URL); ParseTreeNode contentNode = urlNode.firstChild(); SourceModel.CALDoc.TextSegment.Plain content = buildCALDocTextBlockWithoutInlineTags(contentNode); return SourceModel.CALDoc.TextSegment.InlineTag.URL.make(content); } /** * Builds a source model representation of an inline cross-reference in a CALDoc comment from the given ParseTreeNode. * @param linkNode the ParseTreeNode representing an inline cross-reference in a CALDoc comment. * @return a source model representation of an inline cross-reference in a CALDoc comment. */ static SourceModel.CALDoc.TextSegment.InlineTag.Link buildCALDocInlineLinkTagSegment(ParseTreeNode linkNode) { linkNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_LINK); ParseTreeNode linkContextNode = linkNode.firstChild(); switch (linkContextNode.getType()) { case CALTreeParserTokenTypes.CALDOC_TEXT_LINK_FUNCTION: return SourceModel.CALDoc.TextSegment.InlineTag.Link.Function.make(buildCALDocFunctionOrClassMethodCrossReference(linkContextNode.firstChild())); case CALTreeParserTokenTypes.CALDOC_TEXT_LINK_MODULE: return SourceModel.CALDoc.TextSegment.InlineTag.Link.Module.make(buildCALDocModuleCrossReference(linkContextNode.firstChild())); case CALTreeParserTokenTypes.CALDOC_TEXT_LINK_DATACONS: return SourceModel.CALDoc.TextSegment.InlineTag.Link.DataCons.make(buildCALDocDataConsCrossReference(linkContextNode.firstChild())); case CALTreeParserTokenTypes.CALDOC_TEXT_LINK_TYPECONS: return SourceModel.CALDoc.TextSegment.InlineTag.Link.TypeCons.make(buildCALDocTypeConsCrossReference(linkContextNode.firstChild())); case CALTreeParserTokenTypes.CALDOC_TEXT_LINK_TYPECLASS: return SourceModel.CALDoc.TextSegment.InlineTag.Link.TypeClass.make(buildCALDocTypeClassCrossReference(linkContextNode.firstChild())); case CALTreeParserTokenTypes.CALDOC_TEXT_LINK_WITHOUT_CONTEXT: return buildCALDocInlineLinkTagWithoutContextSegment(linkNode); default: throw new IllegalStateException("Unexpected parse tree node " + linkNode.toDebugString() + "."); } } /** * Builds a source model representation of an inline cross-reference in a CALDoc comment that appears without * a 'context' keyword from the given ParseTreeNode. * @param linkNode the ParseTreeNode representing an inline cross-reference in a CALDoc comment. * @return a source model representation of the inline cross-reference in a CALDoc comment that appears without * a 'context' keyword from the given ParseTreeNode. */ static SourceModel.CALDoc.TextSegment.InlineTag.Link.WithoutContext buildCALDocInlineLinkTagWithoutContextSegment(ParseTreeNode linkNode) { ParseTreeNode linkContextNode = linkNode.firstChild(); ParseTreeNode refNode = linkContextNode.firstChild(); switch (refNode.getType()) { case CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_VAR: return SourceModel.CALDoc.TextSegment.InlineTag.Link.FunctionWithoutContext.make( SourceModel.CALDoc.CrossReference.Function.make(buildFunctionName(refNode.firstChild()), false)); case CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_VAR: return SourceModel.CALDoc.TextSegment.InlineTag.Link.FunctionWithoutContext.make( SourceModel.CALDoc.CrossReference.Function.make(buildFunctionName(refNode.firstChild()), true)); case CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_CONS: return SourceModel.CALDoc.TextSegment.InlineTag.Link.ConsNameWithoutContext.makeAnnotated( SourceModel.CALDoc.CrossReference.WithoutContextCons.makeAnnotated( buildWithoutContextConsName(refNode.firstChild()), false, refNode.firstChild().getAssemblySourceRange()), linkNode.getAssemblySourceRange()); case CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_CONS: return SourceModel.CALDoc.TextSegment.InlineTag.Link.ConsNameWithoutContext.makeAnnotated( SourceModel.CALDoc.CrossReference.WithoutContextCons.makeAnnotated( buildWithoutContextConsName(refNode.firstChild()), true, refNode.firstChild().getAssemblySourceRange()), linkNode.getAssemblySourceRange()); default: throw new IllegalStateException("Unexpected parse tree node " + refNode.toDebugString() + "."); } } /** * Builds a source model representation of an identifier that starts with an uppercase character in a scenario * where the context of the identifier (i.e. whether it is a module name, a type constructor name, a data constructor * name or a type class name) is undetermined. * * @param qualifiedConsNode the QUALIFIED_CONS node representing such an identifier. * @return the source model representation of such a name 'without context'. */ static SourceModel.Name.WithoutContextCons buildWithoutContextConsName(ParseTreeNode qualifiedConsNode) { qualifiedConsNode.verifyType(CALTreeParserTokenTypes.QUALIFIED_CONS); ParseTreeNode moduleNameNode = qualifiedConsNode.firstChild(); SourceModel.Name.Module moduleName = buildMaybeEmptyModuleName(moduleNameNode); ParseTreeNode consNameNode = moduleNameNode.nextSibling(); return SourceModel.Name.WithoutContextCons.makeAnnotated(moduleName, consNameNode.getText(), qualifiedConsNode.getAssemblySourceRange()); } /** * Builds a source model representation of an emphasized piece of text in a CALDoc comment from the given ParseTreeNode. * @param emNode the ParseTreeNode representing an emphasized piece of text in a CALDoc comment. * @return a source model representation of an emphasized piece of text in a CALDoc comment. */ static SourceModel.CALDoc.TextSegment.InlineTag.TextFormatting.Emphasized buildCALDocInlineEmTagSegment(ParseTreeNode emNode) { emNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_EMPHASIZED_TEXT); ParseTreeNode contentNode = emNode.firstChild(); SourceModel.CALDoc.TextBlock content = buildCALDocTextBlock(contentNode); return SourceModel.CALDoc.TextSegment.InlineTag.TextFormatting.Emphasized.make(content); } /** * Builds a source model representation of a strongly emphasized piece of text in a CALDoc comment from the given ParseTreeNode. * @param strongNode the ParseTreeNode representing a strongly emphasized piece of text in a CALDoc comment. * @return a source model representation of a strongly emphasized piece of text in a CALDoc comment. */ static SourceModel.CALDoc.TextSegment.InlineTag.TextFormatting.StronglyEmphasized buildCALDocInlineStrongTagSegment(ParseTreeNode strongNode) { strongNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_STRONGLY_EMPHASIZED_TEXT); ParseTreeNode contentNode = strongNode.firstChild(); SourceModel.CALDoc.TextBlock content = buildCALDocTextBlock(contentNode); return SourceModel.CALDoc.TextSegment.InlineTag.TextFormatting.StronglyEmphasized.make(content); } /** * Builds a source model representation of a superscripted piece of text in a CALDoc comment from the given ParseTreeNode. * @param supNode the ParseTreeNode representing a superscripted piece of text in a CALDoc comment. * @return a source model representation of a superscripted piece of text in a CALDoc comment. */ static SourceModel.CALDoc.TextSegment.InlineTag.TextFormatting.Superscript buildCALDocInlineSupTagSegment(ParseTreeNode supNode) { supNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_SUPERSCRIPT_TEXT); ParseTreeNode contentNode = supNode.firstChild(); SourceModel.CALDoc.TextBlock content = buildCALDocTextBlock(contentNode); return SourceModel.CALDoc.TextSegment.InlineTag.TextFormatting.Superscript.make(content); } /** * Builds a source model representation of a subscripted piece of text in a CALDoc comment from the given ParseTreeNode. * @param subNode the ParseTreeNode representing a subscripted piece of text in a CALDoc comment. * @return a source model representation of a subscripted piece of text in a CALDoc comment. */ static SourceModel.CALDoc.TextSegment.InlineTag.TextFormatting.Subscript buildCALDocInlineSubTagSegment(ParseTreeNode subNode) { subNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_SUBSCRIPT_TEXT); ParseTreeNode contentNode = subNode.firstChild(); SourceModel.CALDoc.TextBlock content = buildCALDocTextBlock(contentNode); return SourceModel.CALDoc.TextSegment.InlineTag.TextFormatting.Subscript.make(content); } /** * Builds a source model representation of a "@summary" inline tag segment in a CALDoc comment from the given ParseTreeNode. * @param summaryNode the ParseTreeNode representing a "@summary" inline tag segment in a CALDoc comment. * @return a source model representation of a "@summary" inline tag segment in a CALDoc comment. */ static SourceModel.CALDoc.TextSegment.InlineTag.Summary buildCALDocInlineSummaryTagSegment(ParseTreeNode summaryNode) { summaryNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_SUMMARY); ParseTreeNode contentNode = summaryNode.firstChild(); SourceModel.CALDoc.TextBlock content = buildCALDocTextBlock(contentNode); return SourceModel.CALDoc.TextSegment.InlineTag.Summary.make(content); } /** * Builds a source model representation of a code block in a CALDoc comment from the given ParseTreeNode. * @param codeNode the ParseTreeNode representing a code block in a CALDoc comment. * @return a source model representation of a code block in a CALDoc comment. */ static SourceModel.CALDoc.TextSegment.InlineTag.Code buildCALDocInlineCodeTagSegment(ParseTreeNode codeNode) { codeNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_CODE_BLOCK); ParseTreeNode contentNode = codeNode.firstChild(); SourceModel.CALDoc.TextSegment.Preformatted content = buildCALDocPreformattedBlock(contentNode); return SourceModel.CALDoc.TextSegment.InlineTag.Code.make(content); } /** * Builds a source model representation of a list in a CALDoc comment from the given ParseTreeNode. * @param listNode the ParseTreeNode representing a list in a CALDoc comment. * @return a source model representation of a list in a CALDoc comment. */ static SourceModel.CALDoc.TextSegment.InlineTag.List buildCALDocInlineListTagSegment(ParseTreeNode listNode) { listNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_ORDERED_LIST, CALTreeParserTokenTypes.CALDOC_TEXT_UNORDERED_LIST); List<SourceModel.CALDoc.TextSegment.InlineTag.List.Item> items = new ArrayList<SourceModel.CALDoc.TextSegment.InlineTag.List.Item>(); for (final ParseTreeNode itemNode : listNode) { itemNode.verifyType(CALTreeParserTokenTypes.CALDOC_TEXT_LIST_ITEM); ParseTreeNode itemContentNode = itemNode.firstChild(); SourceModel.CALDoc.TextBlock content = buildCALDocTextBlock(itemContentNode); SourceModel.CALDoc.TextSegment.InlineTag.List.Item item = SourceModel.CALDoc.TextSegment.InlineTag.List.Item.make(content); items.add(item); } SourceModel.CALDoc.TextSegment.InlineTag.List.Item[] itemsArray = items.toArray(SourceModel.CALDoc.TextSegment.InlineTag.List.NO_ITEMS); if (listNode.getType() == CALTreeParserTokenTypes.CALDOC_TEXT_ORDERED_LIST) { return SourceModel.CALDoc.TextSegment.InlineTag.List.Ordered.make(itemsArray); } else { return SourceModel.CALDoc.TextSegment.InlineTag.List.Unordered.make(itemsArray); } } /** * Builds a source model representation of a CALDoc description block from the given ParseTreeNode. * @param descBlockNode the ParseTreeNode representing a CALDoc description block. * @return a source model representation of the CALDoc description block. */ static SourceModel.CALDoc.TextBlock buildCALDocDescriptionBlock(ParseTreeNode descBlockNode) { descBlockNode.verifyType(CALTreeParserTokenTypes.CALDOC_DESCRIPTION_BLOCK); return buildCALDocTextBlock(descBlockNode.firstChild()); } /** * Builds a source model representation of a CALDoc tagged block from the given ParseTreeNode. * @param taggedBlockNode the ParseTreeNode representing a CALDoc tagged block. * @return a source model representation of the CALDoc tagged block. */ static SourceModel.CALDoc.TaggedBlock buildCALDocTaggedBlock(ParseTreeNode taggedBlockNode) { switch (taggedBlockNode.getType()) { case CALTreeParserTokenTypes.CALDOC_AUTHOR_BLOCK: return SourceModel.CALDoc.TaggedBlock.Author.make(buildCALDocTextBlock(taggedBlockNode.firstChild())); case CALTreeParserTokenTypes.CALDOC_DEPRECATED_BLOCK: return SourceModel.CALDoc.TaggedBlock.Deprecated.make(buildCALDocTextBlock(taggedBlockNode.firstChild())); case CALTreeParserTokenTypes.CALDOC_RETURN_BLOCK: return SourceModel.CALDoc.TaggedBlock.Return.make(buildCALDocTextBlock(taggedBlockNode.firstChild())); case CALTreeParserTokenTypes.CALDOC_VERSION_BLOCK: return SourceModel.CALDoc.TaggedBlock.Version.make(buildCALDocTextBlock(taggedBlockNode.firstChild())); case CALTreeParserTokenTypes.CALDOC_ARG_BLOCK: { ParseTreeNode argNameNode = taggedBlockNode.firstChild(); argNameNode.verifyType(CALTreeParserTokenTypes.VAR_ID, CALTreeParserTokenTypes.ORDINAL_FIELD_NAME); return SourceModel.CALDoc.TaggedBlock.Arg.make(buildFieldName(argNameNode), buildCALDocTextBlock(argNameNode.nextSibling())); } case CALTreeParserTokenTypes.CALDOC_SEE_BLOCK: return buildCALDocSeeBlock(taggedBlockNode); default: throw new IllegalStateException("Unexpected parse tree node " + taggedBlockNode.toDebugString() + "."); } } /** * Builds a source model representation of a CALDoc "@see" block from the given ParseTreeNode. * @param taggedBlockNode the ParseTreeNode representing a CALDoc "@see" block. * @return a source model representation of the CALDoc "@see" block. */ static SourceModel.CALDoc.TaggedBlock.See buildCALDocSeeBlock(ParseTreeNode taggedBlockNode) { ParseTreeNode seeBlockNode = taggedBlockNode.firstChild(); switch (seeBlockNode.getType()) { case CALTreeParserTokenTypes.CALDOC_SEE_FUNCTION_BLOCK: { SourceModel.CALDoc.CrossReference.Function[] names = new SourceModel.CALDoc.CrossReference.Function[seeBlockNode.getNumberOfChildren()]; int i = 0; for (final ParseTreeNode nameNode : seeBlockNode) { names[i] = buildCALDocFunctionOrClassMethodCrossReference(nameNode); i++; } return SourceModel.CALDoc.TaggedBlock.See.Function.make(names); } case CALTreeParserTokenTypes.CALDOC_SEE_MODULE_BLOCK: { SourceModel.CALDoc.CrossReference.Module[] names = new SourceModel.CALDoc.CrossReference.Module[seeBlockNode.getNumberOfChildren()]; int i = 0; for (final ParseTreeNode nameNode : seeBlockNode) { names[i] = buildCALDocModuleCrossReference(nameNode); i++; } return SourceModel.CALDoc.TaggedBlock.See.Module.make(names); } case CALTreeParserTokenTypes.CALDOC_SEE_DATACONS_BLOCK: { SourceModel.CALDoc.CrossReference.DataCons[] names = new SourceModel.CALDoc.CrossReference.DataCons[seeBlockNode.getNumberOfChildren()]; int i = 0; for (final ParseTreeNode nameNode : seeBlockNode) { names[i] = buildCALDocDataConsCrossReference(nameNode); i++; } return SourceModel.CALDoc.TaggedBlock.See.DataCons.make(names); } case CALTreeParserTokenTypes.CALDOC_SEE_TYPECONS_BLOCK: { SourceModel.CALDoc.CrossReference.TypeCons[] names = new SourceModel.CALDoc.CrossReference.TypeCons[seeBlockNode.getNumberOfChildren()]; int i = 0; for (final ParseTreeNode nameNode : seeBlockNode) { names[i] = buildCALDocTypeConsCrossReference(nameNode); i++; } return SourceModel.CALDoc.TaggedBlock.See.TypeCons.make(names); } case CALTreeParserTokenTypes.CALDOC_SEE_TYPECLASS_BLOCK: { SourceModel.CALDoc.CrossReference.TypeClass[] names = new SourceModel.CALDoc.CrossReference.TypeClass[seeBlockNode.getNumberOfChildren()]; int i = 0; for (final ParseTreeNode nameNode : seeBlockNode) { names[i] = buildCALDocTypeClassCrossReference(nameNode); i++; } return SourceModel.CALDoc.TaggedBlock.See.TypeClass.make(names); } case CALTreeParserTokenTypes.CALDOC_SEE_BLOCK_WITHOUT_CONTEXT: { SourceModel.CALDoc.CrossReference.CanAppearWithoutContext[] names = new SourceModel.CALDoc.CrossReference.CanAppearWithoutContext[seeBlockNode.getNumberOfChildren()]; int i = 0; for (final ParseTreeNode nameNode : seeBlockNode) { names[i] = buildCALDocCrossReferenceWithoutContext(nameNode); i++; } return SourceModel.CALDoc.TaggedBlock.See.WithoutContext.makeAnnotated(names, taggedBlockNode.getAssemblySourceRange()); } default: throw new IllegalStateException("Unexpected parse tree node " + seeBlockNode.toDebugString() + "."); } } /** * Builds a source model representation of a function name appearing in a CALDoc "@see"/"@link" block from the given ParseTreeNode. * @param refNode the ParseTreeNode representing a function name appearing in a CALDoc "@see"/"@link" block. * @return a source model representation of the function name appearing in a CALDoc "@see"/"@link" block. */ static SourceModel.CALDoc.CrossReference.Function buildCALDocFunctionOrClassMethodCrossReference(ParseTreeNode refNode) { switch (refNode.getType()) { case CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_VAR: return SourceModel.CALDoc.CrossReference.Function.make(buildFunctionName(refNode.firstChild()), false); case CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_VAR: return SourceModel.CALDoc.CrossReference.Function.make(buildFunctionName(refNode.firstChild()), true); default: throw new IllegalStateException("Unexpected parse tree node " + refNode.toDebugString() + "."); } } /** * Builds a source model representation of a module name appearing in a CALDoc "@see"/"@link" block from the given ParseTreeNode. * @param refNode the ParseTreeNode representing a module name appearing in a CALDoc "@see"/"@link" block. * @return a source model representation of the module name appearing in a CALDoc "@see"/"@link" block. */ static SourceModel.CALDoc.CrossReference.Module buildCALDocModuleCrossReference(ParseTreeNode refNode) { switch (refNode.getType()) { case CALTreeParserTokenTypes.CALDOC_UNCHECKED_MODULE_NAME: { ParseTreeNode nameNode = refNode.firstChild(); SourceModel.Name.Module moduleName = buildModuleName(nameNode); return SourceModel.CALDoc.CrossReference.Module.make(moduleName, false); } case CALTreeParserTokenTypes.CALDOC_CHECKED_MODULE_NAME: { ParseTreeNode nameNode = refNode.firstChild(); SourceModel.Name.Module moduleName = buildModuleName(nameNode); return SourceModel.CALDoc.CrossReference.Module.make(moduleName, true); } default: throw new IllegalStateException("Unexpected parse tree node " + refNode.toDebugString() + "."); } } /** * Builds a source model representation of a data constructor name appearing in a CALDoc "@see"/"@link" block from the given ParseTreeNode. * @param refNode the ParseTreeNode representing a data constructor name appearing in a CALDoc "@see"/"@link" block. * @return a source model representation of the data constructor name appearing in a CALDoc "@see"/"@link" block. */ static SourceModel.CALDoc.CrossReference.DataCons buildCALDocDataConsCrossReference(ParseTreeNode refNode) { switch (refNode.getType()) { case CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_CONS: return SourceModel.CALDoc.CrossReference.DataCons.make(buildDataConsName(refNode.firstChild()), false); case CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_CONS: return SourceModel.CALDoc.CrossReference.DataCons.make(buildDataConsName(refNode.firstChild()), true); default: throw new IllegalStateException("Unexpected parse tree node " + refNode.toDebugString() + "."); } } /** * Builds a source model representation of a type constructor name appearing in a CALDoc "@see"/"@link" block from the given ParseTreeNode. * @param refNode the ParseTreeNode representing a type constructor name appearing in a CALDoc "@see"/"@link" block. * @return a source model representation of the type constructor name appearing in a CALDoc "@see"/"@link" block. */ static SourceModel.CALDoc.CrossReference.TypeCons buildCALDocTypeConsCrossReference(ParseTreeNode refNode) { switch (refNode.getType()) { case CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_CONS: return SourceModel.CALDoc.CrossReference.TypeCons.make(buildTypeConsName(refNode.firstChild()), false); case CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_CONS: return SourceModel.CALDoc.CrossReference.TypeCons.make(buildTypeConsName(refNode.firstChild()), true); default: throw new IllegalStateException("Unexpected parse tree node " + refNode.toDebugString() + "."); } } /** * Builds a source model representation of a type class name appearing in a CALDoc "@see"/"@link" block from the given ParseTreeNode. * @param refNode the ParseTreeNode representing a type class name appearing in a CALDoc "@see"/"@link" block. * @return a source model representation of the type class name appearing in a CALDoc "@see"/"@link" block. */ static SourceModel.CALDoc.CrossReference.TypeClass buildCALDocTypeClassCrossReference(ParseTreeNode refNode) { switch (refNode.getType()) { case CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_CONS: return SourceModel.CALDoc.CrossReference.TypeClass.make(buildTypeClassName(refNode.firstChild()), false); case CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_CONS: return SourceModel.CALDoc.CrossReference.TypeClass.make(buildTypeClassName(refNode.firstChild()), true); default: throw new IllegalStateException("Unexpected parse tree node " + refNode.toDebugString() + "."); } } /** * Builds a source model representation of a name appearing in a CALDoc "@see"/"@link" block without context from the given ParseTreeNode. * @param refNode the ParseTreeNode representing a name appearing in a CALDoc "@see"/"@link" block without context. * @return a source model representation of the name appearing in a CALDoc "@see"/"@link" block without context. */ static SourceModel.CALDoc.CrossReference.CanAppearWithoutContext buildCALDocCrossReferenceWithoutContext(ParseTreeNode refNode) { switch (refNode.getType()) { case CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_VAR: return SourceModel.CALDoc.CrossReference.Function.make(buildFunctionName(refNode.firstChild()), false); case CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_VAR: return SourceModel.CALDoc.CrossReference.Function.make(buildFunctionName(refNode.firstChild()), true); case CALTreeParserTokenTypes.CALDOC_UNCHECKED_QUALIFIED_CONS: return SourceModel.CALDoc.CrossReference.WithoutContextCons.makeAnnotated(buildWithoutContextConsName(refNode.firstChild()), false, refNode.firstChild().getSourceRange()); case CALTreeParserTokenTypes.CALDOC_CHECKED_QUALIFIED_CONS: return SourceModel.CALDoc.CrossReference.WithoutContextCons.makeAnnotated(buildWithoutContextConsName(refNode.firstChild()), true, refNode.firstChild().getSourceRange()); default: throw new IllegalStateException("Unexpected parse tree node " + refNode.toDebugString() + "."); } } /** * Builds a source model representation of the list of tagged blocks that form the trailing portion of a CALDoc comment. * @param taggedBlocksNode the ParseTreeNode whose children are nodes representing the tagged blocks of the CALDoc comment. * @return an array whose elements are the source model representations of the tagged blocks. */ static SourceModel.CALDoc.TaggedBlock[] buildCALDocTaggedBlocks(ParseTreeNode taggedBlocksNode) { taggedBlocksNode.verifyType(CALTreeParserTokenTypes.CALDOC_TAGGED_BLOCKS); SourceModel.CALDoc.TaggedBlock[] blocks = new SourceModel.CALDoc.TaggedBlock[taggedBlocksNode.getNumberOfChildren()]; int i = 0; for (final ParseTreeNode blockNode : taggedBlocksNode) { blocks[i] = buildCALDocTaggedBlock(blockNode); i++; } return blocks; } /** * A helper function that determines whether the scope is explicitly specified or is omitted. * @param accessModifierNode * @return whether the scope is explicitly specified in the source. */ private static boolean isScopeExplicitlySpecified(ParseTreeNode accessModifierNode) { accessModifierNode.verifyType(CALTreeParserTokenTypes.ACCESS_MODIFIER); ParseTreeNode scopeNode = accessModifierNode.firstChild(); return scopeNode != null; } }