# 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