class Parser::Parser

Public Class Methods

expect(tokens, toktype) click to toggle source
# File lib/sdx/compiler/parser.rb, line 141
def self.expect(tokens, toktype)
    self.lookahead(tokens, toktype, 0)
end
lookahead(tokens, toktype, n) click to toggle source
# File lib/sdx/compiler/parser.rb, line 134
def self.lookahead(tokens, toktype, n)
    if n >= tokens.size
        return false
    end
    tokens[n][1] == toktype
end
parse(tokens, path, lines) click to toggle source
# File lib/sdx/compiler/parser.rb, line 706
        def self.parse(tokens, path, lines)
            parsed = []
            while State::state == :ok and tokens.size > 0
                e = self.parse_expr tokens
                if e
                    if e[0].nodetype == :require
                        code = nil
                        path.each do |search|
                            begin
                                code = File.read "#{File.join(search, e[0].value)}.sdx"
                            rescue
                                nil
                            end
                        end
                        unless code
                            error "Cannot find file #{e[0].value}.sdx anywhere in path"
                            State::state = :error
                            return nil
                        end
                        tokens = tokens[e[1]..-1]
                        lexed, _ = Lexer.lex code
                        tokens = [*lexed, *tokens]
                    else
                        parsed << e[0]
                        tokens = tokens[e[1]..-1]
                    end
                else
                    error %{
Unexpected token #{tokens[0][1]} at #{tokens[0][2]}:#{tokens[0][3]}
#{" " * tokens[0][2].to_s.size} |
#{tokens[0][2]} | #{lines[tokens[0][2]].rstrip}
#{" " * tokens[0][2].to_s.size} | #{" " * tokens[0][3]}^ here}
                    State::state = :error
                end
            end
            parsed
        end
parse_assign(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 546
def self.parse_assign(tokens)
    total = 0
    unless self.expect tokens, :name
        return nil
    end
    name = tokens[0][0]
    total += 1
    tokens = tokens[1..-1]
    unless self.expect tokens, :eq
        return nil
    end
    eq = tokens[0][0]
    total += 1
    tokens = tokens[1..-1]
    res = self.parse_expr tokens
    unless res
        return nil
    end
    rhs, part = res
    total += part
    [ (Node.new :assign, eq, [name, rhs]), total]
end
parse_block(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 245
def self.parse_block(tokens)
    unless (self.expect tokens, :lbrace)
        return nil
    end
    tokens = tokens[1..-1]
    children = []
    total = 1
    while true
        if self.expect tokens, :rbrace
            total += 1
            return [ (Node.new :block, "", children), total ]
        end
        e = self.parse_expr tokens
        if e
            children << e[0]
            total += e[1]
            tokens = tokens[e[1]..-1]
        else
            puts "Syntax error at token ", tokens[0]
            Kernel.exit 1
        end
    end
    total += 1
    [ (Node.new :block, "", children), total ]
end
parse_bool(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 169
def self.parse_bool(tokens)
    if self.expect tokens, :bool
        [ (Node.new :bool, tokens[0][0], []), 1 ]
    else
        nil
    end
end
parse_call(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 283
def self.parse_call(tokens)
    res = (self.parse_literal tokens)
    unless res
        return nil
    end
    callee = res
    total = callee[1]
    tokens = tokens[total..-1]
    callee = callee[0]
    if self.expect tokens, :lpar
        args = []
        tokens = tokens[1..-1]
        total += 1
        if self.expect tokens, :rpar
            return [ (Node.new :call, callee, args), total + 1 ]
        end
        while true
            res = (self.parse_expr tokens)
            unless res
                return nil
            end
            arg, part = res
            total += part
            tokens = tokens[part..-1]
            args << arg
            if self.expect tokens, :rpar
                tokens = tokens[1..-1]
                total += 1
                break
            end
            unless (self.expect tokens, :comma)
                return nil
            end
            total += 1
            tokens = tokens[1..-1]
        end
        return [ (Node.new :call, callee, args), total ]
    else
        nil
    end
end
parse_expr(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 691
def self.parse_expr(tokens)
    (self.parse_op tokens)  || 
    (self.parse_call tokens) || 
    (self.parse_require tokens) || 
    (self.parse_return tokens) ||
    (self.parse_new tokens) || 
    (self.parse_object tokens) || 
    (self.parse_fn tokens) || 
    (self.parse_assign tokens) || 
    (self.parse_literal tokens) || 
    (self.parse_if tokens) || 
    (self.parse_while tokens) || 
    (self.parse_for tokens)
end
parse_factor(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 453
def self.parse_factor(tokens)
    (self.parse_call tokens) || 
    (self.parse_require tokens) || 
    (self.parse_new tokens) || 
    (self.parse_object tokens) || 
    (self.parse_fn tokens) || 
    (self.parse_assign tokens) || 
    (self.parse_literal tokens) || 
    (self.parse_if tokens) || 
    (self.parse_while tokens) || 
    (self.parse_for tokens)
end
parse_float(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 177
def self.parse_float(tokens)
    if self.expect tokens, :float
        [ (Node.new :float, tokens[0][0], []), 1 ]
    else
        nil
    end
end
parse_fn(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 569
def self.parse_fn(tokens)
    unless self.expect tokens, :fn
        return nil
    end
    total = 1
    tokens = tokens[1..-1]
    unless self.expect tokens, :name
        return nil
    end
    name = tokens[0][0]
    total += 1
    tokens = tokens[1..-1]
    unless self.expect tokens, :lpar
        return nil
    end
    total += 1
    tokens = tokens[1..-1]
    args = []
    while true
        if self.expect tokens, :rpar
            total += 1
            tokens = tokens[1..-1]
            break
        end
        unless self.expect tokens, :name
            return nil
        end
        args << tokens[0][0]
        total += 1
        tokens = tokens[1..-1]
        if self.expect tokens, :rpar
            total += 1
            tokens = tokens[1..-1]
            break
        end
        unless self.expect tokens, :comma
            return nil
        end
        total += 1
        tokens = tokens[1..-1]
    end
    res = self.parse_expr tokens
    unless res
        return nil
    end
    body, part = res
    total += part
    [ (Node.new :fn, name, [args, body]), total ]
end
parse_for(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 425
def self.parse_for(tokens)
    unless self.expect tokens, :for
        return nil
    end
    total = 1
    tokens = tokens[1..-1]
    name = nil
    if self.expect tokens, :name and self.lookahead tokens, :in, 1
        name = tokens[0][0]
        total += 2
        tokens = tokens[2..-1]
    end
    res = self.parse_expr tokens
    unless res
        return nil
    end
    e, part = res
    total += part
    tokens = tokens[part..-1]
    res = self.parse_expr tokens
    unless res
        return nil
    end
    block, part = res
    total += part
    [ (Node.new :for, e, [name, block]), total ]
end
parse_if(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 369
def self.parse_if(tokens)
    unless self.expect tokens, :if
        return nil
    end
    total = 1
    tokens = tokens[1..-1]
    res = self.parse_expr tokens
    unless res
        return nil
    end
    e, part = res
    total += part
    tokens = tokens[part..-1]
    res = self.parse_expr tokens
    unless res
        return nil
    end
    block, part = res
    total += part
    tokens = tokens[part..-1]
    el = nil
    if self.expect tokens, :else
        total += 1
        tokens = tokens[1..-1]
        res = self.parse_expr tokens
        unless res
            return nil
        end
        el, part = res
        total += part
    end
    [ (Node.new :if, e, [block, el]), total ]
end
parse_list(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 212
def self.parse_list(tokens)
    unless (self.expect tokens, :lbrack)
        return nil
    end
    tokens = tokens[1..-1]
    children = []
    total = 1
    while true
        if self.expect tokens, :rbrack
            total += 1
            break
        end
        res = self.parse_expr tokens
        unless res
            return nil
        end
        e, part = res
        children << e
        total += part
        tokens = tokens[part..-1]
        if self.expect tokens, :rbrack
            total += 1
            break
        end
        unless (self.expect tokens, :comma)
            return nil
        end
        total += 1
        tokens = tokens[1..-1]
    end
    [ (Node.new :list, "", children), total ]
end
parse_literal(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 271
def self.parse_literal(tokens)
    (self.parse_block tokens) || 
    (self.parse_bool tokens) || 
    (self.parse_float tokens) || 
    (self.parse_name tokens) || 
    (self.parse_number tokens) || 
    (self.parse_list tokens) || 
    (self.parse_string tokens) || 
    (self.parse_nil tokens) || 
    (self.parse_parens tokens)
end
parse_name(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 145
def self.parse_name(tokens)
    if self.expect tokens, :name
        [ (Node.new :name, tokens[0][0], []), 1 ]
    else
        nil
    end
end
parse_new(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 325
def self.parse_new(tokens)
    unless self.expect tokens, :new
        return nil
    end
    total = 1
    tokens = tokens[1..-1]
    if self.lookahead tokens, :lpar, 1
        res = (self.parse_literal tokens)
        unless res
            return nil
        end
        callee = res
        callee = callee[0]
        args = []
        tokens = tokens[2..-1]
        total += 2
        if self.expect tokens, :rpar
            return [ (Node.new :call, callee, args), total + 1 ]
        end
        while true
            res = (self.parse_expr tokens)
            unless res
                return nil
            end
            arg, part = res
            total += part
            tokens = tokens[part..-1]
            args << arg
            total += 1
            if self.expect tokens, :rpar
                tokens = tokens[1..-1]
                break
            end
            unless (self.expect tokens, :comma)
                return nil
            end
            tokens = tokens[1..-1]
        end
        return [ (Node.new :new, callee, args), total ]
    else
        nil
    end
end
parse_nil(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 153
def self.parse_nil(tokens)
    if self.expect tokens, :nil
        [ (Node.new :nil, tokens[0][0], []), 1 ]
    else
        nil
    end
end
parse_number(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 161
def self.parse_number(tokens)
    if self.expect tokens, :number
        [ (Node.new :number, tokens[0][0], []), 1 ]
    else
        nil
    end
end
parse_object(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 619
def self.parse_object(tokens)
    unless self.expect tokens, :object
        return nil
    end
    total = 1
    tokens = tokens[1..-1]
    unless self.expect tokens, :name
        return nil
    end
    name = tokens[0][0]
    total += 1
    tokens = tokens[1..-1]
    args = []
    if self.expect tokens, :lpar
        total += 1
        tokens = tokens[1..-1]
        while true
            if self.expect tokens, :rpar
                total += 1
                tokens = tokens[1..-1]
                break
            end
            unless self.expect tokens, :name
                return nil
            end
            args << tokens[0][0]
            total += 1
            tokens = tokens[1..-1]
            if self.expect tokens, :rpar
                total += 1
                tokens = tokens[1..-1]
                break
            end
            unless self.expect tokens, :comma
                return nil
            end
            total += 1
            tokens = tokens[1..-1]
        end
    end
    res = self.parse_expr tokens
    unless res
        return nil
    end
    body, part = res
    total += part
    [ (Node.new :object, name, [args, body]), total ]
end
parse_op(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 506
def self.parse_op(tokens)
    total = 0
    res = self.parse_term tokens
    unless res
        return nil
    end
    lhs, part = res
    total += part
    tokens = tokens[part..-1]
    unless self.expect tokens, :l1op
        return [lhs, part]
    end
    op = tokens[0][0]
    total += 1
    tokens = tokens[1..-1]
    res = self.parse_term tokens
    unless res
        return nil
    end
    rhs, part = res
    total += part
    tokens = tokens[part..-1]
    out = (Node.new :op, op, [lhs])
    while self.expect tokens, :l1op
        op = tokens[0][0]
        total += 1
        tokens = tokens[1..-1]
        res = self.parse_term tokens
        unless res
            return nil
        end
        rhs2, part = res
        total += part
        tokens = tokens[part..-1]
        rhs = Node.new :op, op, [rhs, rhs2]
    end
    out.children << rhs
    [out, total]
end
parse_parens(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 193
def self.parse_parens(tokens)
    if self.expect tokens, :lpar
        tokens = tokens[1..-1]
        res = self.parse_expr tokens
        unless res
            return nil
        end
        e, part = self.parse_expr tokens
        tokens = tokens[part..-1]
        res = self.expect tokens, :rpar
        unless res
            return nil
        end
        return [e, part + 2]
    else
        return nil
    end
end
parse_require(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 668
def self.parse_require(tokens)
    unless self.expect tokens, :require
        return nil
    end
    tokens = tokens[1..-1]
    unless self.expect tokens, :string
        return nil
    end
    [ (Node.new :require, tokens[0][0][1..-2], []), 2 ]
end
parse_return(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 679
def self.parse_return(tokens)
    unless self.expect tokens, :return
        return nil
    end
    tokens = tokens[1..-1]
    res = self.parse_expr tokens
    unless res
        return nil
    end
    [ (Node.new :return, res[0], []), res[1] ]
end
parse_string(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 185
def self.parse_string(tokens)
    if self.expect tokens, :string
        [ (Node.new :string, tokens[0][0][1..-2], []), 1 ]
    else
        nil
    end
end
parse_term(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 466
def self.parse_term(tokens)
    total = 0
    res = self.parse_factor tokens
    unless res
        return nil
    end
    lhs, part = res
    total += part
    tokens = tokens[part..-1]
    unless self.expect tokens, :l2op
        return [lhs, part]
    end
    op = tokens[0][0]
    total += 1
    tokens = tokens[1..-1]
    res = self.parse_factor tokens
    unless res
        return nil
    end
    rhs, part = res
    total += part
    tokens = tokens[part..-1]
    out = (Node.new :op, op, [lhs])
    while self.expect tokens, :l2op
        op = tokens[0][0]
        total += 1
        tokens = tokens[1..-1]
        res = self.parse_term tokens
        unless res
            return nil
        end
        rhs2, part = res
        total += part
        tokens = tokens[part..-1]
        rhs = Node.new :op, op, [rhs, rhs2]
    end
    out.children << rhs
    [out, total]
end
parse_while(tokens) click to toggle source
# File lib/sdx/compiler/parser.rb, line 403
def self.parse_while(tokens)
    unless self.expect tokens, :while
        return nil
    end
    total = 1
    tokens = tokens[1..-1]
    res = self.parse_expr tokens
    unless res
        return nil
    end
    e, part = res
    total += part
    tokens = tokens[part..-1]
    res = self.parse_expr tokens
    unless res
        return nil
    end
    block, part = res
    total += part
    [ (Node.new :while, e, [block]), total ]
end