/*
* 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
private func translatePatternChildren(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode,
propInfos: Array<PropInfo>): Array<Pattern> {
let pats = ArrayList<Pattern>()
for (propInfo in propInfos) {
let curNode = (nodeImpl as NonTerminal).getOrThrow().children[propInfo.index]
let offset = propInfo.offset
pats.add(cast<Pattern>(SyntaxNodeImplTranslator.translate(curNode, startPos + offset, parentNode)).getOrThrow())
}
pats.toArray()
}
sealed abstract class Pattern <: SyntaxTreeNode {
init(nodePos: CodePositionRange, nodeImpl: SyntaxNodeImpl, parentNode: ?SyntaxTreeNode,
commentsPropInfo: Array<PropInfo>) {
super(nodePos, nodeImpl, parentNode, commentsPropInfo)
}
init(nodeImpl: SyntaxNodeImpl, hasComment!: Bool = true) {
super(nodeImpl, hasComment: hasComment)
}
}
class ConstPatternPropInfos {
let litConstExprPropInfo: PropInfo
init(litConstExprPropInfo: PropInfo) {
this.litConstExprPropInfo = litConstExprPropInfo
}
}
/**
* @brief ConstPattern class represents a pattern for a constant expression.
*/
public class ConstPattern <: Pattern {
private let startPos: CodePosition
private let propInfos: ConstPatternPropInfos
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode,
propInfos: ConstPatternPropInfos, commentsPropInfo: Array<PropInfo>) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode, commentsPropInfo)
this.startPos = startPos
this.propInfos = propInfos
}
/**
* @brief Initialize node with literal constant expr.
*/
public init(litConstExpr: LitConstExpr, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createConstPatternImpl(litConstExpr, comments: comments))
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<ConstPattern>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.propInfos = redNode.propInfos
this.startPos = startPos
}
/**
* @brief Literal constant expression.
*/
public prop litConstExpr: LitConstExpr {
get() {
let curNode = (nodeImpl as NonTerminal).getOrThrow().children[propInfos.litConstExprPropInfo.index]
let offset = propInfos.litConstExprPropInfo.offset
cast<LitConstExpr>(SyntaxNodeImplTranslator.translate(curNode, startPos + offset, this)).getOrThrow()
}
}
}
class EnumPatternPropInfos {
let enumConstructorPropInfo: PropInfo
let enumTypePropInfo: Option<PropInfo>
let subPatternsPropInfo: Array<PropInfo>
init(enumConstructorPropInfo: PropInfo, enumTypePropInfo: Option<PropInfo>, subPatternsPropInfo: Array<PropInfo>) {
this.enumConstructorPropInfo = enumConstructorPropInfo
this.enumTypePropInfo = enumTypePropInfo
this.subPatternsPropInfo = subPatternsPropInfo
}
}
class EnumPatternPosInfos {
let dotPos: Option<CodePosition>
let lParenPos: Option<CodePosition>
let rParenPos: Option<CodePosition>
let commasPos: Array<CodePosition>
init(dotPos: Option<CodePosition>, lParenPos: Option<CodePosition>, rParenPos: Option<CodePosition>,
commasPos: Array<CodePosition>) {
this.dotPos = dotPos
this.lParenPos = lParenPos
this.rParenPos = rParenPos
this.commasPos = commasPos
}
}
/**
* @brief EnumPattern class represents a pattern for an enumeration case.
*/
public class EnumPattern <: Pattern {
private let startPos: CodePosition
private let propInfos: EnumPatternPropInfos
private let posInfos: EnumPatternPosInfos
/**
* @brief Get the positions of commas in the code.
*
* @return Array<CodePositionRange> containing the positions of commas.
*/
public func getCommasPos(): Array<CodePositionRange> {
let commasPos = ArrayList<CodePositionRange>()
for (comma in posInfos.commasPos) {
commasPos.add(CodePositionRange(comma, comma + SyntaxNodeKind.CommaToken.size))
}
return commasPos.toArray()
}
/**
* @brief Get the position of the dot operator.
*
* @return Option<CodePositionRange> representing the position of the dot operator.
*/
public func getDotPos(): Option<CodePositionRange> {
if (let Some(v) <- posInfos.dotPos) {
return (CodePositionRange(v, v + SyntaxNodeKind.DotToken.size))
}
None
}
/**
* @brief Get the position of the left parenthesis.
*
* @return Option<CodePositionRange> representing the position of the left parenthesis.
*/
public func getLParenPos(): Option<CodePositionRange> {
if (let Some(v) <- posInfos.lParenPos) {
return (CodePositionRange(v, v + SyntaxNodeKind.LParenToken.size))
}
None
}
/**
* @brief Get the position of the right parenthesis.
*
* @return Option<CodePositionRange> representing the position of the right parenthesis.
*/
public func getRParenPos(): Option<CodePositionRange> {
if (let Some(v) <- posInfos.rParenPos) {
return (CodePositionRange(v, v + SyntaxNodeKind.RParenToken.size))
}
None
}
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode, posInfos: EnumPatternPosInfos,
propInfos: EnumPatternPropInfos, commentsPropInfo: Array<PropInfo>) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode, commentsPropInfo)
this.startPos = startPos
this.posInfos = posInfos
this.propInfos = propInfos
}
/**
* @brief Initialize node with enum constructor, enum type and sub-patterns.
*/
public init(enumConstructor: SymbolRef, enumType: Option<CompositeType>, subPatterns: Array<Pattern>,
comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createEnumPatternImpl(enumConstructor, enumType, subPatterns, comments: comments))
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<EnumPattern>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.propInfos = redNode.propInfos
this.posInfos = redNode.posInfos
this.startPos = startPos
}
/**
* @brief The enumeration constructor.
*/
public prop enumConstructor: SymbolRef {
get() {
let curNode = (nodeImpl as NonTerminal).getOrThrow().children[propInfos.enumConstructorPropInfo.index]
let offset = propInfos.enumConstructorPropInfo.offset
cast<SymbolRef>(SyntaxNodeImplTranslator.translate(curNode, startPos + offset, this)).getOrThrow()
}
}
/**
* @brief The prefix type of enum pattern.
*
* For example, `p1.p0.E<Int64>` is the enumType of pattern `p1.p0.E<Int64>.C0(x)`.
*/
public prop enumType: Option<CompositeType> {
get() {
if (let Some(propInfo) <- propInfos.enumTypePropInfo) {
let curNode = (nodeImpl as NonTerminal).getOrThrow().children[propInfo.index]
let offset = propInfo.offset
cast<CompositeType>(SyntaxNodeImplTranslator.translate(curNode, startPos + offset, this)).getOrThrow()
} else {
None
}
}
}
/**
* @brief Sub-patterns for the enumeration pattern.
*/
public prop subPatterns: Array<Pattern> {
get() {
translatePatternChildren(nodeImpl, startPos, this, propInfos.subPatternsPropInfo)
}
}
}
class TuplePatternPropInfos {
let subPatternsPropInfo: Array<PropInfo>
init(subPatternsPropInfo: Array<PropInfo>) {
this.subPatternsPropInfo = subPatternsPropInfo
}
}
class TuplePatternPosInfos {
let lParenPos: CodePosition
let rParenPos: CodePosition
let commasPos: Array<CodePosition>
init(
lParenPos: CodePosition,
rParenPos: CodePosition,
commasPos: Array<CodePosition>
) {
this.lParenPos = lParenPos
this.rParenPos = rParenPos
this.commasPos = commasPos
}
}
/**
* @brief TuplePattern class represents a pattern for a tuple.
*/
public class TuplePattern <: Pattern {
private let startPos: CodePosition
private let propInfos: TuplePatternPropInfos
private let posInfos: TuplePatternPosInfos
/**
* @brief Get the position of the left parenthesis.
*
* @return CodePositionRange representing the position of the left parenthesis.
*/
public func getLParenPos(): CodePositionRange {
CodePositionRange(posInfos.lParenPos, posInfos.lParenPos + SyntaxNodeKind.LParenToken.size)
}
/**
* @brief Get the position of the right parenthesis.
*
* @return CodePositionRange representing the position of the right parenthesis.
*/
public func getRParenPos(): CodePositionRange {
CodePositionRange(posInfos.rParenPos, posInfos.rParenPos + SyntaxNodeKind.RParenToken.size)
}
/**
* @brief Get the positions of commas in the code.
*
* @return Array<CodePositionRange> containing the positions of commas.
*/
public func getCommasPos(): Array<CodePositionRange> {
let commasPos = ArrayList<CodePositionRange>()
for (comma in posInfos.commasPos) {
commasPos.add(CodePositionRange(comma, comma + SyntaxNodeKind.CommaToken.size))
}
return commasPos.toArray()
}
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode, posInfos: TuplePatternPosInfos,
propInfos: TuplePatternPropInfos, commentsPropInfo: Array<PropInfo>) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode, commentsPropInfo)
this.startPos = startPos
this.posInfos = posInfos
this.propInfos = propInfos
}
/**
* @brief Initialize node with sub-patterns.
* @throws Exception if the input 'subPatterns' contains less than 2 elements.
*/
public init(subPatterns: Array<Pattern>, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createTuplePatternImpl(subPatterns, comments: comments))
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<TuplePattern>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.propInfos = redNode.propInfos
this.posInfos = redNode.posInfos
this.startPos = startPos
}
/**
* @brief Sub-patterns for the tuple.
*/
public prop subPatterns: Array<Pattern> {
get() {
translatePatternChildren(nodeImpl, startPos, this, propInfos.subPatternsPropInfo)
}
}
}
class TypePatternPropInfos {
let patternTypePropInfo: PropInfo
let subPatternPropInfo: PropInfo
init(patternTypePropInfo: PropInfo, subPatternPropInfo: PropInfo) {
this.patternTypePropInfo = patternTypePropInfo
this.subPatternPropInfo = subPatternPropInfo
}
}
class TypePatternPosInfos {
let colonPos: CodePosition
init(colonPos: CodePosition) {
this.colonPos = colonPos
}
}
/**
* @brief TypePattern class represents a pattern with a specific type.
*/
public class TypePattern <: Pattern {
private let startPos: CodePosition
private let propInfos: TypePatternPropInfos
/**
* @brief Get the position of the colon.
*
* @return CodePositionRange representing the position of the colon.
*/
public func getColonPos(): CodePositionRange {
CodePositionRange(posInfos.colonPos, posInfos.colonPos + SyntaxNodeKind.RParenToken.size)
}
private let posInfos: TypePatternPosInfos
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode, posInfos: TypePatternPosInfos,
propInfos: TypePatternPropInfos, commentsPropInfo: Array<PropInfo>) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode, commentsPropInfo)
this.startPos = startPos
this.posInfos = posInfos
this.propInfos = propInfos
}
/**
* @brief Initialize node with pattern type and sub-pattern.
*/
public init(subPattern: Pattern, patternType: TypeAnnotation, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createTypePatternImpl(subPattern, patternType, comments: comments))
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<TypePattern>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.propInfos = redNode.propInfos
this.posInfos = redNode.posInfos
this.startPos = startPos
}
/**
* @brief Type annotation for the pattern.
*/
public prop patternType: TypeAnnotation {
get() {
let curNode = (nodeImpl as NonTerminal).getOrThrow().children[propInfos.patternTypePropInfo.index]
let offset = propInfos.patternTypePropInfo.offset
cast<TypeAnnotation>(SyntaxNodeImplTranslator.translate(curNode, startPos + offset, this)).getOrThrow()
}
}
/**
* @brief Sub-pattern associated with the type.
*/
public prop subPattern: Pattern {
get() {
let curNode = (nodeImpl as NonTerminal).getOrThrow().children[propInfos.subPatternPropInfo.index]
let offset = propInfos.subPatternPropInfo.offset
cast<Pattern>(SyntaxNodeImplTranslator.translate(curNode, startPos + offset, this)).getOrThrow()
}
}
}
/**
* @brief VarOrEnumPattern class represents a pattern for a variable or enumeration.
*/
public class VarOrEnumPattern <: Pattern {
private let identifier_: String
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode, identifier_: String,
commentsPropInfo: Array<PropInfo>) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode, commentsPropInfo)
this.identifier_ = identifier_
}
/**
* @brief Initialize node with the identifier.
*/
public init(identifier: String, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createVarOrEnumPatternImpl(identifier, comments: comments))
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<VarOrEnumPattern>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.identifier_ = identifier
}
/**
* @brief Identifier for the variable or enumeration.
*/
public prop identifier: String {
get() {
identifier_
}
}
}
/**
* @brief VarPattern class represents a pattern for a variable.
*/
public class VarPattern <: Pattern {
private let name_: String
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode, name_: String,
commentsPropInfo: Array<PropInfo>) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode, commentsPropInfo)
this.name_ = name_
}
/**
* @brief Initialize node with variable name.
*/
public init(name: String, comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createVarPatternImpl(name, comments: comments))
let startPos = DEFAULT_START_POS
let curNode = (this.nodeImpl as NonTerminal).getOrThrow()
let redNode = cast<VarPattern>(SyntaxNodeImplTranslator.translate(curNode, startPos, None)).getOrThrow()
this.name_ = name
}
/**
* @brief Name of the variable.
*/
public prop name: String {
get() {
name_
}
}
}
/**
* @brief WildcardPattern class represents a wildcard pattern.
*/
public class WildcardPattern <: Pattern {
init(nodeImpl: SyntaxNodeImpl, startPos: CodePosition, parentNode: ?SyntaxTreeNode,
commentsPropInfo: Array<PropInfo>) {
super(CodePositionRange(startPos, startPos + nodeImpl.offset), nodeImpl, parentNode, commentsPropInfo)
}
/**
* @brief Initialize node.
*/
public init(comments!: Array<Comment> = []) {
super(SyntaxNodeImplCreator.createWildcardPatternImpl(comments: comments))
}
}