class Lisp::Parser

Public Class Methods

new() click to toggle source
# File lib/rubylisp/parser.rb, line 5
def initialize
end

Public Instance Methods

make_character(ch) click to toggle source
# File lib/rubylisp/parser.rb, line 28
def make_character(ch)
  Lisp::Character.with_value(ch)
end
make_float(str) click to toggle source
# File lib/rubylisp/parser.rb, line 16
def make_float(str)
  Lisp::Number.with_value(str.to_f)
end
make_hex_number(str) click to toggle source
# File lib/rubylisp/parser.rb, line 12
def make_hex_number(str)
  Lisp::Number.with_value(["0x", str].join.to_i(0))
end
make_number(str) click to toggle source
# File lib/rubylisp/parser.rb, line 8
def make_number(str)
  Lisp::Number.with_value(str.to_i)
end
make_string(str) click to toggle source
# File lib/rubylisp/parser.rb, line 20
def make_string(str)
  Lisp::String.with_value(str)
end
make_symbol(str) click to toggle source
# File lib/rubylisp/parser.rb, line 24
def make_symbol(str)
  Lisp::Symbol.named(str)
end
parse(src) click to toggle source
# File lib/rubylisp/parser.rb, line 248
def parse(src)
  tokenizer = Tokenizer.from_string(src)
  self.parse_sexpr(tokenizer)
end
parse_and_eval(src, env=Lisp::EnvironmentFrame.global) click to toggle source
# File lib/rubylisp/parser.rb, line 259
def parse_and_eval(src, env=Lisp::EnvironmentFrame.global)
  sexpr = self.parse(src)
  return sexpr.evaluate(env)
end
parse_and_eval_all(src, env=Lisp::EnvironmentFrame.global) click to toggle source
# File lib/rubylisp/parser.rb, line 264
def parse_and_eval_all(src, env=Lisp::EnvironmentFrame.global)
  tokenizer = Tokenizer.from_string(src)
  result = nil
  until tokenizer.eof?
    sexpr = self.parse_sexpr(tokenizer)
    result = sexpr.evaluate(env)
  end
  result
end
parse_cons_cell(start_pos, tokens) click to toggle source
# File lib/rubylisp/parser.rb, line 32
def parse_cons_cell(start_pos, tokens)
  pos, tok, lit = tokens.next_token
  if tok == :RPAREN
    tokens.consume_token
    return Lisp::ConsCell.cons().tap do |obj|
      obj.set_location(start_pos, pos - start_pos + 1) if @parse_for_debugging
    end
  end

  car = nil
  cdr = nil
  cells = []
  while tok != :RPAREN
    if tok == :PERIOD
      tokens.consume_token
      cdr = self.parse_sexpr(tokens)
      return nil if tokens.next_token[0] == :EOF
      pos, tok, lit = tokens.next_token
      return Lisp::Debug.process_error("Expected ')' to follow a dotted tail on line #{tokens.line_number}", Lisp::EnvironmentFrame.global) if tok != :RPAREN
      tokens.consume_token
      return Lisp::ConsCell.array_to_list(cells, cdr).tap do |obj|
        obj.set_location(start_pos, pos - start_pos + 1) if @parse_for_debugging
      end
    else
      car = self.parse_sexpr(tokens)
      return Lisp::Debug.process_error("Unexpected EOF (expected ')') on line #{tokens.line_number}", Lisp::EnvironmentFrame.global) if tokens.next_token[0] == :EOF
      cells << car
    end
    pos, tok, lit = tokens.next_token
  end

  tokens.consume_token
  Lisp::ConsCell.array_to_list(cells).tap do |obj|
    obj.set_location(start_pos, pos - start_pos + 1) if @parse_for_debugging
  end
end
parse_frame(start_pos, tokens, literal) click to toggle source
# File lib/rubylisp/parser.rb, line 69
def parse_frame(start_pos, tokens, literal)
  m = {}
  pos, tok, lit = tokens.next_token
  if tok == :RBRACE
    tokens.consume_token
    if literal
      Lisp::Frame.new.tap do |obj|
        obj.set_location(start_pos, pos - start_pos + 1) if @parse_for_debugging
      end
    else
      Lisp::ConsCell.cons(Lisp::Symbol.named("make-frame"), nil).tap do |obj|
        obj.set_location(start_pos, pos - start_pos + 1) if @parse_for_debugging
      end
    end
  else
    cells = []
    while tok != :RBRACE
      item = self.parse_sexpr(tokens)
      return Lisp::Debug.process_error("Unexpected EOF (expected '}') on line #{tokens.line_number}", env) if tokens.next_token[0] == :EOF
      cells << item
      pos, tok, lit = tokens.next_token
    end
    
    tokens.consume_token
    keys_and_values = Lisp::ConsCell.array_to_list(cells)
    if literal
      Lisp::PrimFrame.make_frame_impl(keys_and_values, Lisp::EnvironmentFrame.global).tap do |obj|
        obj.set_location(start_pos, pos - start_pos + 1) if @parse_for_debugging
      end
    else
      Lisp::ConsCell.cons(Lisp::Symbol.named("make-frame"), keys_and_values).tap do |obj|
        obj.set_location(start_pos, pos - start_pos + 1) if @parse_for_debugging
      end
    end
  end
end
parse_object_from_file(port, env=Lisp::EnvironmentFrame.global) click to toggle source
# File lib/rubylisp/parser.rb, line 253
def parse_object_from_file(port, env=Lisp::EnvironmentFrame.global)
  tokenizer = Tokenizer.from_file(port)
  result = self.parse_sexpr(tokenizer)
  result.nil? ? Lisp::EofObject.instance : result
end
parse_sexpr(tokens) click to toggle source
# File lib/rubylisp/parser.rb, line 145
def parse_sexpr(tokens)
  while true
    pos, tok, lit = tokens.next_token
    # puts "token: <#{tok}, #{lit}>"
    return nil if tok == :EOF
    tokens.consume_token
    case tok
    when :COMMENT
      next
    when :NUMBER
      return make_number(lit).tap do |obj|
        obj.set_location(pos, lit.length) if @parse_for_debugging
      end
    when :FLOAT
      return make_float(lit).tap do |obj|
        obj.set_location(pos, lit.length) if @parse_for_debugging
      end
    when :HEXNUMBER
      return make_hex_number(lit).tap do |obj|
        obj.set_location(pos, lit.length) if @parse_for_debugging
      end
    when :STRING
      return make_string(lit).tap do |obj|
        obj.set_location(pos, lit.length) if @parse_for_debugging
      end
    when :CHARACTER
      return make_character(lit).tap do |obj|
        obj.set_location(pos, lit.length) if @parse_for_debugging
      end
    when :LPAREN
      return parse_cons_cell(pos, tokens)
    when :LBRACE
      return parse_frame(pos, tokens, false)
    when :QUOTE_LBRACE
      return parse_frame(pos, tokens, true)
    when :HASH_LPAREN
      return parse_vector(pos, tokens, false)
    when :QUOTE_HASH_LPAREN
      return parse_vector(pos, tokens, true)
    when :SYMBOL
      return make_symbol(lit).tap do |obj|
        obj.set_location(pos, lit.length) if @parse_for_debugging
      end
    when :FFI_NEW_SYMBOL
      return Lisp::FfiNew.new(lit).tap do |obj|
        obj.set_location(pos, lit.length) if @parse_for_debugging
      end
    when :FFI_SEND_SYMBOL
      return Lisp::FfiSend.new(lit).tap do |obj|
        obj.set_location(pos, lit.length) if @parse_for_debugging
      end
    when :FFI_STATIC_SYMBOL
      return Lisp::FfiStatic.new(lit).tap do |obj|
    obj.set_location(pos, lit.length) if @parse_for_debugging
      end
    when :FALSE
      if @parse_for_debugging
        return Lisp::Boolean.with_value(false).tap do |obj|
          obj.set_location(pos, 2) if @parse_for_debugging
        end
      else
        return Lisp::FALSE
      end
    when :TRUE
      if @parse_for_debugging
        return Lisp::Boolean.with_value(false).tap do |obj|
          obj.set_location(pos, 2) if @parse_for_debugging
        end
      else
        return Lisp::TRUE
      end
    when :QUOTE
      expr = parse_sexpr(tokens)
      return Lisp::ConsCell.array_to_list([Lisp::Symbol.named('quote'), expr]).tap do |obj|
        obj.set_location(pos, expr.src_length + 1) if @parse_for_debugging
      end
    when :BACKQUOTE
      expr = parse_sexpr(tokens)
      return Lisp::ConsCell.array_to_list([Lisp::Symbol.named('quasiquote'), expr]).tap do |obj|
        obj.set_location(pos, expr.src_length + 1) if @parse_for_debugging
      end
    when :COMMA
      expr = parse_sexpr(tokens)
      return Lisp::ConsCell.array_to_list([Lisp::Symbol.named('unquote'), expr]).tap do |obj|
        obj.set_location(pos, expr.src_length + 1) if @parse_for_debugging
      end
    when :COMMAAT
      expr = parse_sexpr(tokens)
      return Lisp::ConsCell.array_to_list([Lisp::Symbol.named('unquote-splicing'), expr]).tap do |obj|
        obj.set_location(pos, expr.src_length + 2) if @parse_for_debugging
      end
    when :WHITESPACE
      next
    when :ILLEGAL
      return Lisp::Debug.process_error("Illegal token: #{lit} on line #{tokens.line_number}", Lisp::EnvironmentFrame.global)
    else
      return make_symbol(lit).tap do |obj|
        obj.set_location(pos, lit.length) if @parse_for_debugging
      end
    end
  end
end
parse_vector(start_pos, tokens, literal) click to toggle source
# File lib/rubylisp/parser.rb, line 107
def parse_vector(start_pos, tokens, literal)
  v = []
  pos, tok, lit = tokens.next_token
  if tok == :RPAREN
    tokens.consume_token
    if literal
      Lisp::Vector.new.tap do |obj|
        obj.set_location(start_pos, pos - start_pos + 1) if @parse_for_debugging
      end
    else
      Lisp::ConsCell.cons(Lis::Symbol.named("vector"), nil).tap do |obj|
        obj.set_location(start_pos, pos - start_pos + 1) if @parse_for_debugging
      end
    end
  else
    cells = []
    while tok != :RPAREN
      item = self.parse_sexpr(tokens)
      return Lisp::Debug.process_error("Unexpected EOF (expected ')') on line #{tokens.line_number}", env) if tokens.next_token[0] == :EOF
      cells << item
      pos, tok, lit = tokens.next_token
    end
    
    tokens.consume_token
    
    if literal
      Lisp::Vector.with_array(cells).tap do |obj|
        obj.set_location(start_pos, pos - start_pos + 1) if @parse_for_debugging
      end
    else
      Lisp::ConsCell.cons(Lisp::Symbol.named("vector"), Lisp::ConsCell.array_to_list(cells)).tap do |obj|
        obj.set_location(start_pos, pos - start_pos + 1) if @parse_for_debugging
      end
    end
  end
end
process_file(fname) click to toggle source
# File lib/rubylisp/parser.rb, line 274
def process_file(fname)
  File.open(fname) do |f|
    parse_and_eval_all(f.read)
  end
end