/*
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* This source file is part of the Cangjie project, licensed under Apache-2.0
* with Runtime Library Exception.
*
* See https://cangjie-lang.cn/pages/LICENSE for license information.
*/
package stdx.syntax
import std.collection.ArrayList
import std.collection.collectString
/**
* @brief Enum representing different kinds of imports.
*/
public enum ImportKind {
| Alias
| All
| Multi
| Single
| ...
}
/**
* @brief Represents position information for import aliases.
*/
class ImportAliasPosInfos {
let identifierPos: CodePosition
let asPos: CodePosition
let aliasNamePos: CodePosition
init(identifierPos: CodePosition, asPos: CodePosition, aliasNamePos: CodePosition) {
this.identifierPos = identifierPos
this.asPos = asPos
this.aliasNamePos = aliasNamePos
}
}
/**
* @brief Represents an import alias, which extends from ImportContent.
*/
public class ImportAlias <: ImportContent {
private let aliasName_: String
private let identifier_: String
/**
* @brief The position information for the import alias.
*/
private let posInfos: ImportAliasPosInfos
/**
* @brief Gets the position range of the identifier in the import alias.
*
* @return A CodePositionRange representing the position range of the identifier.
*/
public func getIdentifierPos(): CodePositionRange {
let endPos = posInfos.identifierPos + identifier.size
return CodePositionRange(posInfos.identifierPos, endPos)
}
/**
* @brief Gets the position range of the 'as' keyword in the import alias.
*
* @return A CodePositionRange representing the position range of the 'as' keyword.
*/
public func getAsPos(): CodePositionRange {
let endPos = posInfos.asPos + SyntaxNodeKind.AsToken.size
return CodePositionRange(posInfos.asPos, endPos)
}
/**
* @brief Gets the position range of the alias name in the import alias.
*
* @return A CodePositionRange representing the position range of the alias name.
*/
public func getAliasNamePos(): CodePositionRange {
let endPos = posInfos.aliasNamePos + aliasName.size
return CodePositionRange(posInfos.aliasNamePos, endPos)
}
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode, posInfos: ImportAliasPosInfos,
importContentPosInfos: ImportContentPosInfos, aliasName_: String, identifier_: String, prefixes_: Array<String>,
commentsPropInfo: Array<PropInfo>) {
super(nodeImpl, startPos, parentNode, importContentPosInfos, prefixes_, commentsPropInfo)
this.posInfos = posInfos
this.aliasName_ = aliasName_
this.identifier_ = identifier_
}
/**
* @brief Initialize node with prefixes, package name and alias name.
*/
public init(prefixes: Array<String>, identifier: String, alias: String, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createImportAliasImpl(prefixes, identifier, alias, comments: comments), prefixes)
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<ImportAlias>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.posInfos = redNode.posInfos
this.aliasName_ = alias
this.identifier_ = identifier
}
/**
* @brief The name of the alias.
*/
public prop aliasName: String {
get() {
aliasName_
}
}
/**
* @brief The identifier of the import alias.
*/
public prop identifier: String {
get() {
identifier_
}
}
}
/**
* @brief Represents information about multiple positions.
*/
class ImportAllPosInfos {
/**
* @brief The multiple positions stored in the ImportAllPosInfos.
*/
let mulPos: CodePosition
init(mulPos: CodePosition) {
this.mulPos = mulPos
}
}
/**
* @brief Represents an import of all elements, extending ImportContent.
*/
public class ImportAll <: ImportContent {
private let posInfos: ImportAllPosInfos
/**
* @brief Gets the position range of the 'mul' token in the import content.
*
* @return A CodePositionRange representing the position range of the 'mul' token.
*/
public func getMulPos(): CodePositionRange {
let endPos = posInfos.mulPos + SyntaxNodeKind.MulToken.size
return CodePositionRange(posInfos.mulPos, endPos)
}
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode, posInfos: ImportAllPosInfos,
importContentPosInfos: ImportContentPosInfos, prefixes_: Array<String>, commentsPropInfo: Array<PropInfo>) {
super(nodeImpl, startPos, parentNode, importContentPosInfos, prefixes_, commentsPropInfo)
this.posInfos = posInfos
}
/**
* @brief Initialize node with prefixes.
*/
public init(prefixes: Array<String>, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createImportAllImpl(prefixes, comments: comments), prefixes)
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<ImportAll>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.posInfos = redNode.posInfos
}
}
/**
* @brief Represents information about positions in import content.
*/
class ImportContentPosInfos {
/**
* @brief The positions of dots in the import content.
*/
let dotsPos: Array<CodePosition>
/**
* @brief The positions of prefixes in the import content.
*/
let prefixesPos: Array<CodePosition>
init(dotsPos: Array<CodePosition>, prefixesPos: Array<CodePosition>) {
this.dotsPos = dotsPos
this.prefixesPos = prefixesPos
}
}
/**
* @brief Represents an import content node in the syntax tree.
*/
public open class ImportContent <: SyntaxTreeNode {
internal let startPos: CodePosition
/**
* @brief The position information for the import content.
*/
private let posInfos: ImportContentPosInfos
private let prefixes_: Array<String>
/**
* @brief Gets the position ranges of dots in the import content.
*
* @return An array of CodePositionRange representing the positions of dots.
*/
public func getDotsPos(): Array<CodePositionRange> {
let size = posInfos.dotsPos.size
let ret = Array<CodePositionRange>(size, repeat: CodePositionRange())
for (i in 0..size) {
let endPos = posInfos.dotsPos[i] + SyntaxNodeKind.DotToken.size
ret[i] = CodePositionRange(posInfos.dotsPos[i], endPos)
}
ret
}
/**
* @brief Gets the position ranges of prefixes in the import content.
*
* @return An array of CodePositionRange representing the positions of prefixes.
*/
public func getPrefixesPos(): Array<CodePositionRange> {
let size = posInfos.prefixesPos.size
let ret = Array<CodePositionRange>(size, repeat: CodePositionRange())
for (i in 0..size) {
let endPos = posInfos.prefixesPos[i] + prefixes[i].size
ret[i] = CodePositionRange(posInfos.prefixesPos[i], endPos)
}
ret
}
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode, posInfos: ImportContentPosInfos,
prefixes_: Array<String>, commentsPropInfo: Array<PropInfo>) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode, commentsPropInfo)
this.startPos = startPos
this.posInfos = posInfos
this.prefixes_ = prefixes_
}
init(nodeImpl: SyntaxNodeImpl, prefixes: Array<String>, hasComment!: Bool = true) {
super(nodeImpl, hasComment: hasComment)
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<ImportContent>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.prefixes_ = prefixes
this.startPos = startPos
this.posInfos = redNode.posInfos
}
/**
* @brief The prefixes of the import content.
*/
public prop prefixes: Array<String> {
get() {
prefixes_
}
}
}
/**
* @brief Represents position information for an import list.
*/
class ImportListPosInfos {
let importKeyWordPos: CodePosition
init(importKeyWordPos: CodePosition) {
this.importKeyWordPos = importKeyWordPos
}
}
class ImportListPropInfos {
let contentsPropInfo: PropInfo
let modifierPropInfo: Option<PropInfo>
init(contentsPropInfo: PropInfo, modifierPropInfo: Option<PropInfo>) {
this.contentsPropInfo = contentsPropInfo
this.modifierPropInfo = modifierPropInfo
}
}
/**
* @brief Represents a list of imports, extending SyntaxTreeNode.
*/
public class ImportList <: SyntaxTreeNode {
private let startPos: CodePosition
private let kind_: ImportKind
private let posInfos: ImportListPosInfos
private let propInfos: ImportListPropInfos
/**
* @brief Gets the position range of the 'import' keyword in the import statement.
*
* @return A CodePositionRange representing the position range of the 'import' keyword.
*/
public func getImportKeyWordPos(): CodePositionRange {
let endPos = posInfos.importKeyWordPos + SyntaxNodeKind.ImportToken.size
return CodePositionRange(posInfos.importKeyWordPos, endPos)
}
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode, posInfos: ImportListPosInfos,
propInfos: ImportListPropInfos, kind_: ImportKind, commentsPropInfo: Array<PropInfo>) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode, commentsPropInfo)
this.startPos = startPos
this.posInfos = posInfos
this.propInfos = propInfos
this.kind_ = kind_
}
/**
* @brief Initialize node with imported content, import kind and modifier.
*/
public init(contents: ImportContent, modifier: Option<Modifier>, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createImportListImpl(contents, modifier, comments: comments))
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<ImportList>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.startPos = startPos
this.kind_ = redNode.kind
this.propInfos = redNode.propInfos
this.posInfos = redNode.posInfos
}
/**
* @brief Contents of the import.
*/
public prop contents: ImportContent {
get() {
let propInfo = propInfos.contentsPropInfo
let curNode = (nodeImpl as NonTerminal).getOrThrow().children[propInfo.index]
cast<ImportContent>(SyntaxNodeImplTranslator.translate(curNode, startPos + propInfo.offset, this))
.getOrThrow()
}
}
/**
* @brief Kind of import.
*/
public prop kind: ImportKind {
get() {
kind_
}
}
/**
* @brief Modifier for the import.
*/
public prop modifier: Option<Modifier> {
get() {
if (let Some(propInfo) <- propInfos.modifierPropInfo) {
let curNode = (nodeImpl as NonTerminal).getOrThrow().children[propInfo.index]
cast<Modifier>(SyntaxNodeImplTranslator.translate(curNode, startPos + propInfo.offset, this))
.getOrThrow()
} else {
None
}
}
}
}
/**
* @brief Represents position information for a multi-import statement.
*/
class ImportMultiPosInfos {
let lCurlPos: CodePosition
let rCurlPos: CodePosition
let commasPos: Array<CodePosition>
init(lCurlPos: CodePosition, rCurlPos: CodePosition, commasPos: Array<CodePosition>) {
this.lCurlPos = lCurlPos
this.rCurlPos = rCurlPos
this.commasPos = commasPos
}
}
class ImportMultiPropInfos {
let contentsPropInfo: PropInfo
init(contentsPropInfo: PropInfo) {
this.contentsPropInfo = contentsPropInfo
}
}
/**
* @brief Represents a multi-import statement, which extends from ImportContent.
*/
public class ImportMulti <: ImportContent {
/**
* @brief CodePosition information for the multi-import statement.
*/
private let posInfos: ImportMultiPosInfos
private let propInfos: ImportMultiPropInfos
/**
* @brief Gets the position range of the left Curl in the multi-import statement.
*
* @return A CodePositionRange representing the position range of the left Curl.
*/
public func getLCurlPos(): CodePositionRange {
let endPos = posInfos.lCurlPos + SyntaxNodeKind.LCurlToken.size
return CodePositionRange(posInfos.lCurlPos, endPos)
}
/**
* @brief Gets the position range of the right Curl in the multi-import statement.
*
* @return A CodePositionRange representing the position range of the right Curl.
*/
public func getRCurlPos(): CodePositionRange {
let endPos = posInfos.rCurlPos + SyntaxNodeKind.RCurlToken.size
return CodePositionRange(posInfos.rCurlPos, endPos)
}
/**
* @brief Gets the position ranges of the commas in the multi-import statement.
*
* @return An Array of CodePositionRange representing the position ranges of the commas.
*/
public func getCommasPos(): Array<CodePositionRange> {
let size = posInfos.commasPos.size
let ret = Array<CodePositionRange>(size, repeat: CodePositionRange())
for (i in 0..size) {
let endPos = posInfos.commasPos[i] + SyntaxNodeKind.CommaToken.size
ret[i] = CodePositionRange(posInfos.commasPos[i], endPos)
}
ret
}
/**
* @brief Initializes a new instance of ImportMulti.
*
* @param prefixes The prefixes of the multi-import statement.
* @param contents The list of import contents.
*/
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode, posInfos: ImportMultiPosInfos,
propInfos: ImportMultiPropInfos, importContentPosInfos: ImportContentPosInfos, prefixes_: Array<String>,
commentsPropInfo: Array<PropInfo>) {
super(nodeImpl, startPos, parentNode, importContentPosInfos, prefixes_, commentsPropInfo)
this.posInfos = posInfos
this.propInfos = propInfos
}
/**
* @brief Initialize node with prefixes, package name and sub package import contents.
*/
public init(prefixes: Array<String>, contents: Array<ImportContent>, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createImportMultiImpl(prefixes, contents, comments: comments), prefixes)
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<ImportMulti>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.posInfos = redNode.posInfos
this.propInfos = redNode.propInfos
}
/**
* @brief List of import contents.
*/
public prop contents: Array<ImportContent> {
get() {
let importContents = ArrayList<ImportContent>()
let lp = LocalParser((nodeImpl as NonTerminal).getOrThrow().children, propInfos.contentsPropInfo.offset,
index: propInfos.contentsPropInfo.index)
let kinds = [SyntaxNodeKind.ImportSingle, SyntaxNodeKind.ImportAll, SyntaxNodeKind.ImportAlias]
while (let Some(kind) <- lp.look(kinds)) {
if (let Some(node) <- lp.consume(kind: kind)) {
importContents.add(
cast<ImportContent>(SyntaxNodeImplTranslator.translate(node, startPos + lp.offset, this))
.getOrThrow())
lp.moveOffset(node)
}
lp.moveOffset(lp.lookAndConsume(SyntaxNodeKind.CommaToken))
}
importContents.toArray()
}
}
}
/**
* @brief Represents position information for a single import identifier.
*/
class ImportSinglePosInfos {
/**
* @brief The position of the identifier in the import statement.
*/
let identifierPos: CodePosition
init(identifierPos: CodePosition) {
this.identifierPos = identifierPos
}
}
/**
* @brief Represents a single import statement, which extends from ImportContent.
*/
public class ImportSingle <: ImportContent {
private let posInfos: ImportSinglePosInfos
private let identifier_: String
/**
* @brief Gets the position range of the identifier in the import statement.
*
* @return A CodePositionRange representing the position range of the identifier.
*/
public func getIdentifierPos(): CodePositionRange {
let endPos = posInfos.identifierPos + identifier.size
return CodePositionRange(posInfos.identifierPos, endPos)
}
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode, posInfos: ImportSinglePosInfos,
importContentPosInfos: ImportContentPosInfos, identifier_: String, prefixes_: Array<String>,
commentsPropInfo: Array<PropInfo>) {
super(nodeImpl, startPos, parentNode, importContentPosInfos, prefixes_, commentsPropInfo)
this.posInfos = posInfos
this.identifier_ = identifier_
}
/**
* @brief Initialize node with prefixes, package name and alias name.
*/
public init(prefixes: Array<String>, identifier: String, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createImportSingleImpl(prefixes, identifier, comments: comments), prefixes)
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<ImportSingle>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.identifier_ = identifier
this.posInfos = redNode.posInfos
}
/**
* @brief The identifier for the import.
*/
public prop identifier: String {
get() {
identifier_
}
}
}
/**
* @brief Class representing a package in the syntax tree.
*
* This class extends SyntaxTreeNode and contains information about a package,
* including its name, whether it is a macro package, and its source files.
*/
public class Package <: SyntaxTreeNode {
private let name_: String
private let isMacroPkg_: Bool
private let srcFileImpls: Array<(SyntaxNodeImpl, String)>
init(isMacroPkg_: Bool, name_: String, srcFileImpls: Array<(SyntaxNodeImpl, String)>) {
super(CodePositionRange(), NonTerminal(SyntaxNodeKind.Package), None)
this.isMacroPkg_ = isMacroPkg_
this.name_ = name_
this.srcFileImpls = srcFileImpls
}
/**
* @brief Initialize a new Package node.
*/
public init(isMacroPkg: Bool, name: String, srcFile: Array<SourceFile>) {
super(CodePositionRange(), Terminal(SyntaxNodeKind.Invalid), None)
let (isMacro, pkgName) = checkPackage(ArrayList(srcFile))
if (isMacro != isMacroPkg || pkgName != name) {
throw Exception("InitException: the input params are illegal for Package Init.")
}
this.isMacroPkg_ = isMacroPkg
this.name_ = name
let fileImpls = ArrayList<(SyntaxNodeImpl, String)>()
for (file in srcFile) {
fileImpls.add((file.nodeImpl, file.path))
}
this.srcFileImpls = fileImpls.toArray()
}
/**
* @brief Returns a string representation of the package.
*
* @return A string representation of the package, include the file name and file content.
*/
public func toString(): String {
var res: String = ""
let srcFile_ = srcFile
let size = srcFile_.size
for (i in 0..size) {
res += "// " + srcFile_[i].name + NEWLINE
if (i < size - 1) {
res += srcFile_[i].toString() + NEWLINE
} else {
res += srcFile_[i].toString()
}
}
res
}
public func toTokens(): Tokens {
var tks = Tokens()
let srcFile_ = srcFile
let size = srcFile_.size
for (i in 0..size) {
tks += Token(TokenKind.COMMENT, NEWLINE + "// " + srcFile_[i].name + NEWLINE)
tks += srcFile_[i].toTokens()
}
tks
}
/**
* @brief Indicates if the package is a macro package.
*
* This boolean field specifies whether the package is a macro package.
*/
public prop isMacroPkg: Bool {
get() {
isMacroPkg_
}
}
/**
* @brief The name of the package.
*
* This string field holds the name of the package.
*/
public prop name: String {
get() {
name_
}
}
/**
* @brief The source files of the package.
*
* This array field contains the source files associated with the package.
*/
public prop srcFile: Array<SourceFile> {
get() {
let srcFile = ArrayList<SourceFile>()
for ((impl, path) in srcFileImpls) {
if (let Some(fileNode) <- SyntaxNodeImplTranslator.translateFile(impl, path, parent: this)) {
if (let Some(file) <- (fileNode as SourceFile)) {
srcFile.add(file)
}
}
}
srcFile.toArray()
}
}
}
class PackageHeaderPropInfos {
let accessModifierPropInfo: Option<PropInfo>
init(accessModifierPropInfo: Option<PropInfo>) {
this.accessModifierPropInfo = accessModifierPropInfo
}
}
class PackageHeaderPosInfos {
let macroKeyWordPos: Option<CodePosition>
let packageKeyWordPos: CodePosition
let pkgIdentifiersPos: Array<CodePosition>
let dotsPos: Array<CodePosition>
init(macroKeyWordPos: Option<CodePosition>, packageKeyWordPos: CodePosition, pkgIdentifiersPos: Array<CodePosition>,
dotsPos: Array<CodePosition>) {
this.macroKeyWordPos = macroKeyWordPos
this.packageKeyWordPos = packageKeyWordPos
this.pkgIdentifiersPos = pkgIdentifiersPos
this.dotsPos = dotsPos
}
}
/**
* @brief Represents a package header, extending SyntaxTreeNode.
*/
public class PackageHeader <: SyntaxTreeNode {
private let isMacroPkg_: Bool
private let packageNameIdentifiers_: Array<String>
private let startPos: CodePosition
private let propInfos: PackageHeaderPropInfos
private let posInfos: PackageHeaderPosInfos
/**
* @brief Returns array of position ranges for dot tokens in the package path
*
* @param none
* @return Array of CodePositionRange objects for dot tokens
*
* @throws none
*/
public func getDotsPos(): Array<CodePositionRange> {
let size = posInfos.dotsPos.size
let ret = Array<CodePositionRange>(size, repeat: CodePositionRange())
for (i in 0..size) {
let endPos = posInfos.dotsPos[i] + SyntaxNodeKind.DotToken.size
ret[i] = CodePositionRange(posInfos.dotsPos[i], endPos)
}
ret
}
/**
* @brief Returns optional position range for macro keyword if present
*
* @param none
* @return CodePositionRange if macro keyword exists, None otherwise
*
* @throws none
*/
public func getMacroKeyWordPos(): Option<CodePositionRange> {
if (let Some(v) <- posInfos.macroKeyWordPos) {
let endPos = v + SyntaxNodeKind.MacroToken.size
return CodePositionRange(v, endPos)
}
return None
}
/**
* @brief Returns array of position ranges for each package identifier token
*
* @param none
* @return Array of CodePositionRange objects for package name identifiers
*
* @throws none
*/
public func getPackageIdentifiersPos(): Array<CodePositionRange> {
let size = posInfos.pkgIdentifiersPos.size
let ret = Array<CodePositionRange>(size, repeat: CodePositionRange())
for (i in 0..size) {
let endPos = posInfos.pkgIdentifiersPos[i] + packageNameIdentifiers[i].size
ret[i] = CodePositionRange(posInfos.pkgIdentifiersPos[i], endPos)
}
ret
}
/**
* @brief Returns position range for package keyword token
*
* @param none
* @return CodePositionRange for "package" keyword
*
* @throws none
*/
public func getPackageKeyWordPos(): CodePositionRange {
let endPos = posInfos.packageKeyWordPos + SyntaxNodeKind.PackageToken.size
CodePositionRange(posInfos.packageKeyWordPos, endPos)
}
/**
* @brief Returns fully qualified package name from identifier array
*
* @param none
* @return Last element of packageNameIdentifiers as the main package name
*
* @throws none
*/
public func getPackageName(): String {
return packageNameIdentifiers[packageNameIdentifiers.size - 1]
}
/**
* @brief Returns parent package name by joining all but last identifier
*
* @param none
* @return Concatenated parent package name string
*
* @throws none
*/
public func getParentPackageName(): String {
return collectString<String>(delimiter: ".")(packageNameIdentifiers[..packageNameIdentifiers.size - 1])
}
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode, isMacroPkg_: Bool,
packageNameIdentifiers_: Array<String>, posInfos: PackageHeaderPosInfos, propInfos: PackageHeaderPropInfos,
commentsPropInfo: Array<PropInfo>) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode, commentsPropInfo)
this.isMacroPkg_ = isMacroPkg_
this.packageNameIdentifiers_ = packageNameIdentifiers_
this.startPos = startPos
this.posInfos = posInfos
this.propInfos = propInfos
}
/**
* @brief Initialize a new PackageHeader node.
*/
public init(accessModifier: Option<Modifier>, isMacroPkg: Bool, packageNameIdentifiers: Array<String>,
comments!: Array<Comment> = []) {
super(
SyntaxNodeImplCreator.createPackageHeaderImpl(accessModifier, isMacroPkg, packageNameIdentifiers,
comments: comments))
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<PackageHeader>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.startPos = startPos
this.isMacroPkg_ = isMacroPkg
this.packageNameIdentifiers_ = packageNameIdentifiers
this.propInfos = redNode.propInfos
this.posInfos = redNode.posInfos
}
/**
* @brief Access modifier for the package.
*/
public prop accessModifier: Option<Modifier> {
get() {
if (let Some(propInfo) <- propInfos.accessModifierPropInfo) {
let curNode = (nodeImpl as NonTerminal).getOrThrow().children[propInfo.index]
let offset = propInfo.offset
cast<Modifier>(SyntaxNodeImplTranslator.translate(curNode, startPos + offset, this)).getOrThrow()
} else {
None
}
}
}
/**
* @brief Flag for macro package.
*/
public prop isMacroPkg: Bool {
get() {
isMacroPkg_
}
}
/**
* @brief Identifiers for the package header.
*/
public prop packageNameIdentifiers: Array<String> {
get() {
packageNameIdentifiers_
}
}
}
class FeatureIdPosInfos {
FeatureIdPosInfos(let ftrIdIdentifiersPos: Array<CodePosition>, let dotsPoses: Array<CodePosition>) {}
}
/**
* @brief Represents a feature id and contains information about
* feature identifiers and dots, extending SyntaxTreeNode.
*/
public class FeatureId <: SyntaxTreeNode {
private let featureNameIdentifiers_: Array<String>
private let posInfos: FeatureIdPosInfos
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode,
featureNameIdentifiers: Array<String>, posInfos: FeatureIdPosInfos) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode)
this.featureNameIdentifiers_ = featureNameIdentifiers
this.posInfos = posInfos
}
/**
* @brief Initialize a new FeatureId node.
*/
public init(identifiers: Array<String>, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createFeatureIdImpl(identifiers, comments: comments))
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let retNode = cast<FeatureId>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.featureNameIdentifiers_ = retNode.featureNameIdentifiers
this.posInfos = retNode.posInfos
}
/**
* @brief Gets the position range of identifiers in the feature id.
*
* @param none
* @return An Array of CodePositionRange representing the position ranges of the identifiers.
*
* @throws none
*/
public func getIdentifierPos(): Array<CodePositionRange> {
let size = posInfos.ftrIdIdentifiersPos.size
let ret = Array<CodePositionRange>(size, repeat: CodePositionRange())
for (i in 0..size) {
let endPos = posInfos.ftrIdIdentifiersPos[i] + featureNameIdentifiers_[i].size
ret[i] = CodePositionRange(posInfos.ftrIdIdentifiersPos[i], endPos)
}
ret
}
/**
* @brief Gets the position range of the dots in the feature id.
*
* @param none
* @return An Array of CodePositionRange representing the position ranges of the dots.
*
* @throws none
*/
public func getDotPoses(): Array<CodePositionRange> {
let size = posInfos.dotsPoses.size
let ret = Array<CodePositionRange>(size, repeat: CodePositionRange())
for (i in 0..size) {
let endPos = posInfos.dotsPoses[i] + SyntaxNodeKind.DotToken.size
ret[i] = CodePositionRange(posInfos.dotsPoses[i], endPos)
}
ret
}
/**
* @brief Gets the value of identifiers in the feature id.
*/
public prop featureNameIdentifiers: Array<String> {
get() {
return featureNameIdentifiers_
}
}
}
class FeaturesSetPosInfos {
FeaturesSetPosInfos(let lCurlPos: CodePosition,
let rCurlPos: CodePosition, let commaPoses: Array<CodePosition>) {}
}
class FeaturesSetPropInfos {
FeaturesSetPropInfos(let contentPropInfos: Array<PropInfo>) {}
}
/**
* @brief Represents a features set and contains information about
* used features, extending SyntaxTreeNode.
*/
public class FeaturesSet <: SyntaxTreeNode {
private let startPos: CodePosition
private let posInfos: FeaturesSetPosInfos
private let propInfos: FeaturesSetPropInfos
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode,
posInfos: FeaturesSetPosInfos, propInfos: FeaturesSetPropInfos) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode)
this.startPos = startPos
this.posInfos = posInfos
this.propInfos = propInfos
}
/**
* @brief Initialize a new FeaturesSet node.
*/
public init(features: Array<FeatureId>, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createFeaturesSetImpl(features, comments: comments))
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let retNode = cast<FeaturesSet>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.startPos = startPos
this.posInfos = retNode.posInfos
this.propInfos = retNode.propInfos
}
/**
* @brief Gets the position ranges of the '{' in the features set.
*
* @param none
* @return A CodePositionRange representing the position ranges of the '{'.
*
* @throws none
*/
public func getLCurlPos(): CodePositionRange {
let endPos = posInfos.lCurlPos + SyntaxNodeKind.LCurlToken.size
return CodePositionRange(posInfos.lCurlPos, endPos)
}
/**
* @brief Gets the position ranges of the '}' in the features set.
*
* @param none
* @return A CodePositionRange representing the position ranges of the '}'.
*
* @throws none
*/
public func getRCurlPos(): CodePositionRange {
let endPos = posInfos.rCurlPos + SyntaxNodeKind.RCurlToken.size
return CodePositionRange(posInfos.rCurlPos, endPos)
}
/**
* @brief Gets the position ranges of the commas in the features set.
*
* @param none
* @return An Array of CodePositionRange representing the position ranges of the commas.
*
* @throws none
*/
public func getCommaPoses(): Array<CodePositionRange> {
let size = posInfos.commaPoses.size
let ret = Array<CodePositionRange>(size, repeat: CodePositionRange())
for (i in 0..size) {
let endPos = posInfos.commaPoses[i] + SyntaxNodeKind.CommaToken.size
ret[i] = CodePositionRange(posInfos.commaPoses[i], endPos)
}
ret
}
/**
* @brief Gets the content of the features set.
*/
public prop content: Array<FeatureId> {
get() {
let ret = ArrayList<FeatureId>()
for (propInfo in propInfos.contentPropInfos) {
let curNode = (nodeImpl as NonTerminal).getOrThrow().children[propInfo.index]
ret.add(
cast<FeatureId>(SyntaxNodeImplTranslator.translate(curNode, startPos + propInfo.offset, this))
.getOrThrow()
)
}
return ret.toArray()
}
}
}
class FeaturesDirectivePosInfos {
FeaturesDirectivePosInfos(let featuresKeywordPos: CodePosition) {}
}
class FeaturesDirectivePropInfos {
FeaturesDirectivePropInfos(let featuresSetPropInfo: PropInfo) {}
}
/**
* @brief Represents a features directive and contains information
* about declared features in the source file, extending SyntaxTreeNode.
*/
public class FeaturesDirective <: SyntaxTreeNode {
private let startPos: CodePosition
private let posInfos: FeaturesDirectivePosInfos
private let propInfos: FeaturesDirectivePropInfos
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode,
posInfos: FeaturesDirectivePosInfos, propInfos: FeaturesDirectivePropInfos) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode)
this.startPos = startPos
this.posInfos = posInfos
this.propInfos = propInfos
}
/**
* @brief Initialize a new FeaturesDirective node.
*/
public init(annotations: Array<Annotation>, set: FeaturesSet, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createFeaturesDirectiveImpl(annotations, set, comments: comments))
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let retNode = cast<FeaturesDirective>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.startPos = startPos
this.posInfos = retNode.posInfos
this.propInfos = retNode.propInfos
}
/**
* @brief Gets the position range of the 'features' keyword in the features directive.
*
* @param none
* @return A CodePositionRange representing the position range of the 'features' keyword.
*
* @throws none
*/
public func getFeaturesKeywordPos(): CodePositionRange {
let endPos = posInfos.featuresKeywordPos + SyntaxNodeKind.FeaturesToken.size
return CodePositionRange(posInfos.featuresKeywordPos, endPos)
}
/**
* @brief Gets an array of annotations in the features directive.
*/
public prop annotations: Array<Annotation> {
get() {
var annos = Array<Annotation>()
if (let Some(node) <- (nodeImpl as NonTerminal)) {
var offset = Offset()
let lp = LocalParser(node.children, offset)
if (let Some(v) <- lp.lookAndConsume(SyntaxNodeKind.AnnotationList)) {
annos = SyntaxNodeImplTranslator.translateList<Annotation>(v,
CodePosition(nodePos.beginLine, nodePos.beginColumn, FileInfos(nodePos.fileName, nodePos.filePath)) +
lp.offset, this)
}
}
return annos
}
}
/**
* @brief Gets the features set with information about declared features in the features directive.
*/
public prop featuresSet: FeaturesSet {
get() {
let propInfo = propInfos.featuresSetPropInfo
let curNode = (nodeImpl as NonTerminal).getOrThrow().children[propInfo.index]
let ftrSet = cast<FeaturesSet>(SyntaxNodeImplTranslator.translate(curNode, startPos + propInfo.offset, this))
.getOrThrow()
return ftrSet
}
}
}