git @ Cat's Eye Technologies Velo / master src / velo / ast.rb
master

Tree @master (Download .tar.gz)

ast.rb @masterraw · history · blame

# Copyright (c) 2012-2024, Chris Pressey, Cat's Eye Technologies.
# This file is distributed under a 2-clause BSD license.  See LICENSES/ dir.
# SPDX-License-Identifier: LicenseRef-BSD-2-Clause-X-Velo

require 'velo/debug'

require 'velo/runtime'

debug "loading ast"

class AST
  def eval obj, args
    # abstract
  end
end

class Script < AST
  def initialize exprs
    @exprs = exprs
  end

  def eval obj, args
    debug "eval #{self} on #{obj} with #{args}"
    e = nil
    for expr in @exprs
      e = expr.eval obj, args
    end
    e
  end

  def to_s
    text = "Script(\n"
    for e in @exprs
      text += "  " + e.to_s + ",\n"
    end
    text + ")"
  end
end

class Assignment < AST
  def initialize object, field, expr
    @object = object
    @field = field
    @expr = expr
  end

  def eval obj, args
    debug "eval #{self} on #{obj} with #{args}"
    val = @expr.eval obj, args
    receiver = @object.eval obj, args
    debug "setting #{@field} on #{receiver}"
    receiver.set @field, val
    val
  end

  def to_s
    "Assignment(#{@object},#{@field},#{@expr})"
  end
end

# This is great... we have an AST node that doesn't correspond to any part
# of the concrete syntax.  (It corresponds to the 'implicit self'.)
class Self < AST
  def eval obj, args
    debug "eval #{self} on #{obj} with #{args}"
    obj
  end

  def to_s
    "Self()"
  end
end

class Lookup < AST
  def initialize receiver, ident
    @receiver = receiver
    @ident = ident
  end

  def receiver
    @receiver
  end

  def ident
    @ident
  end

  def eval obj, args
    debug "eval #{self} on #{obj} with #{args}"
    receiver = @receiver.eval obj, args
    receiver.lookup @ident
  end

  def to_s
    "Lookup(#{@receiver},'#{@ident}')"
  end
end

class MethodCall < AST
  def initialize method_expr, exprs
    @method_expr = method_expr
    @exprs = exprs
  end

  def eval obj, args
    debug "eval #{self} on #{obj} with #{args}"
    new_args = []
    for expr in @exprs
      new_args.push(expr.eval obj, args)
    end
    method = @method_expr.eval obj, args
    debug "arguments evaluated, now calling #{@method_expr} -> #{method}"
    if method.is_a? VeloMethod
      # xxx show receiver (method's bound object) in debug
      debug "running real method #{method} w/args #{args}"
      method.run new_args
    else
      debug "just returning non-method (#{method}) on call"
      method
    end
  end

  def to_s
    text = "MethodCall(#{@method_expr},"
    for e in @exprs
      text += e.to_s + ","
    end
    text + ")"
  end
end

class Argument < AST
  def initialize num
    @num = num-1
  end

  def eval obj, args
    debug "eval #{self} on #{obj} with #{args}"
    args[@num]
  end

  def to_s
    "Argument(#{@num})"
  end
end

class StringLiteral < AST
  def initialize text
    @text = text
  end

  def eval obj, args
    debug "eval #{self} on #{obj} with #{args}"
    make_string_literal @text
  end

  def to_s
    "StringLiteral('#{@text}')"
  end
end