Can Someone Please Tell Me Why I Get This Error?

Here's the code:


import Cocoa
protocol ExprNode: CustomStringConvertible {
}
enum Token {
    case number(Int)
    case plus
    case minus
    case multiply
    case divide
}
struct TokenStruct {
    var token: Token
    var position: Int
}
class Lexer {
    enum Error: Swift.Error {
        case invalidCharacter(Character, pos: Int)
    }
    let input: String.CharacterView
    var position: String.CharacterView.Index
    var indexes = [Int]()

    init(input: String) {
        self.input = input.characters
        self.position = self.input.startIndex
    }
    func peek() -> Character? {
        guard position < input.endIndex else {
            return nil
        }
        return input[position]
    }
    func advance() {
        assert(position < input.endIndex, "Cannot advance past endIndex!")
        position = input.index(after: position)
    }
    func getNumber() -> Int {
        var value = 0
     
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0" ... "9":
                /
                let digitValue = Int(String(nextCharacter))!
                value = 10*value + digitValue
                advance()
             
            default:
                /
                return value
            }
        }
        return value
    }
    func lex() throws -> [TokenStruct] {
        var tokens = [TokenStruct]()
     
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0"..."9":
                let posChar = input.distance(from: input.startIndex, to: position)
                let value = getNumber()
                tokens.append(TokenStruct(token: .number(value), position: posChar))
            case "+":
                let posChar = input.distance(from: input.startIndex, to: position)
                tokens.append(TokenStruct(token: .plus, position: posChar))
                advance()
            case "-":
                let posChar = input.distance(from: input.startIndex, to: position)
                tokens.append(TokenStruct(token: .minus, position: posChar))
                advance()
            case "*":
                let posChar = input.distance(from: input.startIndex, to: position)
                tokens.append(TokenStruct(token: .multiply, position: posChar))
                advance()
            case "/":
                let posChar = input.distance(from: input.startIndex, to: position)
                tokens.append(TokenStruct(token: .divide, position: posChar))
                advance()
             
            case " ":
                /
                advance()
            default:
                let distanceToPosition = input.distance(from: input.startIndex, to: position)
                throw Lexer.Error.invalidCharacter(nextCharacter, pos: distanceToPosition)
            }
        }
        return tokens
    }
}
class Parser {
    enum Error: Swift.Error {
        case unexpectedEndOfInput
        case invalidToken(TokenStruct)
    }
    /
    let tokens: [TokenStruct]
    var position = 0

    init(tokens: [TokenStruct]) {
        self.tokens = tokens
    }
    func getNextToken() -> TokenStruct? {
        guard position < tokens.count else {
            return nil
        }
        func getNumber() throws -> Int {
            guard let token = getNextToken() else {
                throw Parser.Error.unexpectedEndOfInput
            }
            switch token.token {
            case .number(let value):
                return value
            case .plus, .minus, .multiply, .divide:
                throw Parser.Error.invalidToken(token)
            }
        }
        func peekNextToken() -> TokenStruct?
        {
            guard position < tokens.count else
            {
                return nil
            }
            let token = tokens[position]
            return token
        }
     
        func parse() throws -> Int
        {
            var value = try parseMultiplyDivide()
         
            while let token = getNextToken()
            {
                switch token.token
                {
                case .plus:
                    let nextNumber = try parseMultiplyDivide()
                    value += nextNumber
                 
                case .minus:
                    let nextNumber = try parseMultiplyDivide()
                    value -= nextNumber
                 
                case .multiply, .divide, .number:
                    throw Parser.Error.invalidToken(token)
                }
            }
    return value
}
     
func parseMultiplyDivide() throws -> Int
        {
            /
            var value = try getNumber()
         
            while let token = peekNextToken()
            {
                switch token.token
                {
                case .plus, .minus:
                    return value
                 
                case .multiply:
                    getNextToken()
                    let nextNumber = try getNumber()
                    value *= nextNumber
                 
                case .divide:
                    getNextToken()
                    let nextNumber = try getNumber()
                    value /= nextNumber
                 
                 
                case .number:
                    throw Parser.Error.invalidToken(token)
                }
            }
            return value
        }
    }
}
func evaluate(_ input: String) {
    print("Evaluating: \(input)")
    let lexer = Lexer(input: input)

    do {
        let tokens = try lexer.lex()
        print("Lexer output: \(tokens)")
        let parser = Parser(tokens: tokens)
        let result = try Parser.parse()
        print("Parser output: \(result)")
    } catch Lexer.Error.invalidCharacter(let character, let posErr) {
        print("Input contained an invalid character at index \(posErr): \(character)")
    } catch Parser.Error.unexpectedEndOfInput {
        print("Unexpected end of input during parsing")
    } catch Parser.Error.invalidToken(let token) {
        print("Invalid token \(token.token) during parsing at index: \(token.position)")
    } catch {
        print("An error occured: \(error)")
    }
}
evaluate("10 * 3 + 5 * 3")


 



and I get the error:

Type 'Parser' has no member 'parse' in line 191


The function 'parse' is clearly above the evaluation. I don't understand??

Accepted Reply

>> More troubleshooting I guess


Not really. You have a scoping problem. Any function defined inside another function (like "getNumber") is private to the outer function. So, if you move "parseMultiplyDivide" out to the class level, it can no longer access "getNumber", etc.


None of your nested functions need to be nested, so you'd be better off moving them all out to the top level in the class. Those which exist only for other functions in the class to use (and are not to be called from code outside the class) can be marked "private" to prevent outside access.

Replies

It's an instance function, so it must be applied to an instance of the "Parser" class, not the class itself.


You created an instance on line 190, so the correct code would be:


        let result = try parser.parse()

You have defined parse() inside getNextToken()


So, it is not visible outside this function.


If you define it at higher level, that should work


class Parser {
    enum Error: Swift.Error {
        case unexpectedEndOfInput
        case invalidToken(TokenStruct)
    }
   
    let tokens: [TokenStruct]
    var position = 0
   
    init(tokens: [TokenStruct]) {
        self.tokens = tokens
    }


    func parse() throws -> Int
    {
        var value = try parseMultiplyDivide()
       
        while let token = getNextToken()
        {
            switch token.token
            {
            case .plus:
                let nextNumber = try parseMultiplyDivide()
                value += nextNumber
               
            case .minus:
                let nextNumber = try parseMultiplyDivide()
                value -= nextNumber
               
            case .multiply, .divide, .number:
                throw Parser.Error.invalidToken(token)
            }
        }
        return value
    }
   
    func getNextToken() -> TokenStruct? {
        guard position < tokens.count else {
            return nil
        }
        func getNumber() throws -> Int {
            guard let token = getNextToken() else {
                throw Parser.Error.unexpectedEndOfInput
            }
            switch token.token {
            case .number(let value):
                return value
            case .plus, .minus, .multiply, .divide:
                throw Parser.Error.invalidToken(token)
            }
        }
        func peekNextToken() -> TokenStruct?
        {
            guard position < tokens.count else
            {
                return nil
            }
            let token = tokens[position]
            return token
        }

Oh, good catch. I didn't pay enough attention to the indenting. 🙂

Your catch is good as well !

Still showing the error

I defined it at higher level and it fixed the error on line 191. Now it shows 3 errors on lines 104, 111, 115:


Use of unresolved identifier 'parseMultiplyDivide'


Due to that error, I went to define 'parseMultiplyDivide' at a higher level and it gave me errors for the getNumber() function. It's like a cycle of errors. I guess it's some sort of error within the functions themselves:


import Cocoa
protocol ExprNode: CustomStringConvertible {
}
enum Token {
    case number(Int)
    case plus
    case minus
    case multiply
    case divide
}
struct TokenStruct {
    var token: Token
    var position: Int
}
class Lexer {
    enum Error: Swift.Error {
        case invalidCharacter(Character, pos: Int)
    }
    let input: String.CharacterView
    var position: String.CharacterView.Index
    var indexes = [Int]()

    init(input: String) {
        self.input = input.characters
        self.position = self.input.startIndex
    }
    func peek() -> Character? {
        guard position < input.endIndex else {
            return nil
        }
        return input[position]
    }
    func advance() {
        assert(position < input.endIndex, "Cannot advance past endIndex!")
        position = input.index(after: position)
    }
    func getNumber() -> Int {
        var value = 0
     
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0" ... "9":
                let digitValue = Int(String(nextCharacter))!
                value = 10*value + digitValue
                advance()
             
            default:
                return value
            }
        }
        return value
    }
    func lex() throws -> [TokenStruct] {
        var tokens = [TokenStruct]()
     
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0"..."9":
                let posChar = input.distance(from: input.startIndex, to: position)
                let value = getNumber()
                tokens.append(TokenStruct(token: .number(value), position: posChar))
            case "+":
                let posChar = input.distance(from: input.startIndex, to: position)
                tokens.append(TokenStruct(token: .plus, position: posChar))
                advance()
            case "-":
                let posChar = input.distance(from: input.startIndex, to: position)
                tokens.append(TokenStruct(token: .minus, position: posChar))
                advance()
            case "*":
                let posChar = input.distance(from: input.startIndex, to: position)
                tokens.append(TokenStruct(token: .multiply, position: posChar))
                advance()
            case "/":
                let posChar = input.distance(from: input.startIndex, to: position)
                tokens.append(TokenStruct(token: .divide, position: posChar))
                advance()
             
            case " ":
                    advance()
            default:
                let distanceToPosition = input.distance(from: input.startIndex, to: position)
                throw Lexer.Error.invalidCharacter(nextCharacter, pos: distanceToPosition)
            }
        }
        return tokens
    }
}
class Parser {
    enum Error: Swift.Error {
        case unexpectedEndOfInput
        case invalidToken(TokenStruct)
    }
    let tokens: [TokenStruct]
    var position = 0

    init(tokens: [TokenStruct]) {
        self.tokens = tokens
    }
    func parse() throws -> Int
    {
        var value = try parseMultiplyDivide()
     
        while let token = getNextToken()
        {
            switch token.token
            {
            case .plus:
                let nextNumber = try parseMultiplyDivide()
                value += nextNumber
             
            case .minus:
                let nextNumber = try parseMultiplyDivide()
                value -= nextNumber
             
            case .multiply, .divide, .number:
                throw Parser.Error.invalidToken(token)
            }
        }
        return value
    }
    func getNextToken() -> TokenStruct? {
        guard position < tokens.count else {
            return nil
        }
        func getNumber() throws -> Int {
            guard let token = getNextToken() else {
                throw Parser.Error.unexpectedEndOfInput
            }
            switch token.token {
            case .number(let value):
                return value
            case .plus, .minus, .multiply, .divide:
                throw Parser.Error.invalidToken(token)
            }
        }
        func peekNextToken() -> TokenStruct?
        {
            guard position < tokens.count else
            {
                return nil
            }
            let token = tokens[position]
            return token
        }
     
        func parseMultiplyDivide() throws -> Int
        {
            var value = try getNumber()
         
            while let token = peekNextToken()
            {
                switch token.token
                {
                case .plus, .minus:
                    return value
                 
                case .multiply:
                    getNextToken()
                    let nextNumber = try getNumber()
                    value *= nextNumber
                 
                case .divide:
                    getNextToken()
                    let nextNumber = try getNumber()
                    value /= nextNumber
                 
                 
                case .number:
                    throw Parser.Error.invalidToken(token)
                }
            }
            return value
        }
    }
}
func evaluate(_ input: String) {
    print("Evaluating: \(input)")
    let lexer = Lexer(input: input)

    do {
        let tokens = try lexer.lex()
        print("Lexer output: \(tokens)")
        let parser = Parser(tokens: tokens)
        let result = try parser.parse()
        print("Parser output: \(result)")
    } catch Lexer.Error.invalidCharacter(let character, let posErr) {
        print("Input contained an invalid character at index \(posErr): \(character)")
    } catch Parser.Error.unexpectedEndOfInput {
        print("Unexpected end of input during parsing")
    } catch Parser.Error.invalidToken(let token) {
        print("Invalid token \(token.token) during parsing at index: \(token.position)")
    } catch {
        print("An error occured: \(error)")
    }
}
evaluate("10 * 3 + 5 * 3")


More troubleshooting I guess

>> More troubleshooting I guess


Not really. You have a scoping problem. Any function defined inside another function (like "getNumber") is private to the outer function. So, if you move "parseMultiplyDivide" out to the class level, it can no longer access "getNumber", etc.


None of your nested functions need to be nested, so you'd be better off moving them all out to the top level in the class. Those which exist only for other functions in the class to use (and are not to be called from code outside the class) can be marked "private" to prevent outside access.

Thanks a lot man it runs now