sexp = object.new
# Keep track of sexp types by name
sexp.types = [:]
sexp.init = { name |
my.name = name
}
sexp.prototype.to_s = {
"s#{[my.name] + my.nodes}"
}
sexp.prototype.== = { rhs |
m = my
true? rhs.has_method?(:name) && rhs.has_method?(:nodes)
{ m.name == rhs.name && { m.nodes == rhs.nodes } }
}
sexp.prototype.<< = { val |
my.nodes << val
my
}
sexp.prototype.concat = { val |
my.nodes.concat val
my
}
sexp.prototype.last = {
my.nodes.last
}
# Shared initializer for sexp types
initializer = { nodes |
my.nodes = nodes
true? my.nodes.length == 1
{ my.value = nodes.last }
}
# Create new sexp with methods to access the given methods.
make = { name, *meths |
new_thing = sexp.new(name)
meths.each_with_index { name, i |
new_thing.prototype.add_method name, {
nodes[i]
}
}
new_thing.init = ->initializer
sexp.types[name] = new_thing
}
make :program
make :var_assign, :lhs, :rhs
make :local_var_assign, :lhs, :rhs
make :local_var_reassign, :lhs, :rhs
make :upvar_assign, :lhs, :rhs
make :number
make :array
make :hash
make :regex, :body, :opts
make :string
make :string_eval, :value
make :string_interp
make :simple_string
make :symbol
make :simple_symbol
make :function, :args, :body
make :arg, :id
make :def_arg, :id, :value
make :var_arg, :id
make :call, :target, :method, :args
make :simple_index_get, :target, :method, :args
make :simple_index_set, :target, :method, :args
make :get_value
make :get_local_value
make :get_up_value
make :invoke, :target, :args
make :invoke_local, :empty, :method, :args
make :invoke_up, :empty, :method, :args
make :invoke_self, :empty, :method, :args
make :invoke_numbers, :lhs, :op, :rhs
make :invoke_number, :lhs, :op, :rhs
make :invoke_number_rhs, :lhs, :op, :rhs
make :invoke_index_get, :target, :args
make :invoke_function, :target, :args
make :field_assign, :lhs, :rhs
make :field_access, :target, :field
make :binop, :lhs, :op, :rhs
make :meth_access, :target, :method
make :meth_access_local, :target, :method
make :meth_access_up, :target, :method
make :named_arg, :key, :value
# Little shortcut to make sexps via s[...]
s = object.new
s.get = { name, *args |
sexp.types[name].new args
}
sexp? = { val |
val.has_method?(:name) && { sexp.types[val.name] }
}
export ->sexp?, :sexp?
export s, :s