diff --git a/src/server/parser/parser.ts b/src/server/parser/parser.ts index 3da1167..c0a3625 100644 --- a/src/server/parser/parser.ts +++ b/src/server/parser/parser.ts @@ -68,6 +68,8 @@ import ASTVisibility, ASTParams, ASTReturnType, + ASTEnum, + ASTEnumMember, ASTTemplate, ASTFunction, ASTOperator, @@ -1714,6 +1716,74 @@ export class Parser return result } + parseEnumDef(): Result + { + const token = this.lexer.token.clone() + const match = this.match(TokenType.enumDef) + if (!match) + return Err('UnreachableState') + + const ident = this.parseIdent() + if (!ident.isDefined()) + return Err('InvalidTokenSequence') + if (ident.isErr() || ident.isInvalid()) + return ident + + const enumName = ident.val + // If the symbol's already in the table but is not a function symbol, that's an error + if (enumName.symbol && !enumName.symbol.type.mask(SymbolTypes.enum)) + return Err('SymbolAlreadyDefined') + enumName.symbol = new MangroveSymbol(enumName.value, new SymbolType(SymbolTypes.enum | SymbolTypes.type)) + this.symbolTable.insert(enumName.symbol) + + const block = this.parseBlock({allowExtStmt: false, isEnum: true}) + if (!block.isDefined()) + return Err('InvalidTokenSequence') + if (block.isErr() || block.isInvalid()) + return block + const astBlock = block.val as ASTBlock + const enumMembers = astBlock.statements + const valuesValid = enumMembers.every(value => value.valid) + if (enumMembers && !valuesValid) + this.symbolTable.pop(this) + return Ok(new ASTEnum(token, enumName, enumMembers as ASTEnumMember[])) + } + + parseEnumMember(): Result + { + let value + if (this.lexer.token.typeIsOneOf(TokenType.comma)) + this.lexer.next() + this.skipWhite() + const token = this.lexer.token + const ident = this.parseIdent() + if (!ident.isDefined()) + return Err('InvalidTokenSequence') + if (ident.isErr() || ident.isInvalid()) + return ident + // Parse the actual enum value + this.skipWhite() + if (this.lexer.token.typeIsOneOf(TokenType.assignOp)) + { + this.lexer.next() + this.skipWhite() + value = this.parseInt() + } + + if (value) + { + if (!value.isDefined) + return Err('InvalidTokenSequence') + + if (value.isErr() || value.isInvalid()) + return Err('InvalidAssignment') + + return Ok(new ASTEnumMember(token, ident.val, value.val)) + } + + return Ok(new ASTEnumMember(token, ident.val)) + } + parseFunctionDef(): Result { const functionToken = this.lexer.token.clone() @@ -1854,6 +1924,8 @@ export class Parser const token = this.lexer.token if (config.allowExtStmt && token.typeIsOneOf(TokenType.visibility)) return this.parseVisibility() + if (config.isEnum) + return this.parseEnumMember() if (token.typeIsOneOf(TokenType.fromStmt)) return this.parseImportStmt() if (token.typeIsOneOf(TokenType.ifStmt)) @@ -1862,6 +1934,8 @@ export class Parser return this.parseForStmt() if (token.typeIsOneOf(TokenType.whileStmt)) return this.parseWhileStmt() + if (token.typeIsOneOf(TokenType.enumDef)) + return this.parseEnumDef() const stmt = this.parseDefine() if (stmt.isInvalid())