lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


"David Jeske" <jeske@chat.net> writes:

> On Mon, Jul 30, 2001 at 09:29:31AM -0400, Jay Carlson wrote:
> > David Jeske writes:
> >
> > > I would be far happier if I had a mechanism for making my class system
> > > have more bearable syntax. However, I recognize the likely-hood of Lua
> > > ending up with the meta-syntax mechanisms that I think would go so
> > > well with it's meta-language mechanisms is about zero. :)
> >
> > What does your class system look like?
>
> Below is a real example of a class (cut and pasted right out of my
> game project) which inherits from three 'trait/mixin' style base
> classes.

I've written some sugar and rewritten your example.  I have no idea whether
you think this is an improvement or not, but I like it better.

> > What help do you need from the syntax?
>
>   1) Personally, I find languages with task-dedicated syntax
>      easier to use and read. If you dedicate your life to
>      writing ASTs directly by coding in LISP or Scheme you
>      may disagree with me. Please just agree to disagree and
>      move on to the next email in your inbox.

No, that's John Ramsdell....well, he's gotten better.  :-)

>   3) If you forget something or make a syntax mistake inside a
>      function deep within the table, the lack of keywords for
>      the compiler to get it's bearings sometimes makes the syntax
>      errors obtuse.

Yeah, run into that.

>   4) Personally I find the syntax ugly, and hard to read.

Me too.

> > Do you need reader macros, or can you get away with runtime
> > interpretation?
>
> I'm not sure what you mean by runtime interpretation.

Well, I was thinking of leaning on the use of strings and somewhat
reflective features, but I don't have a good example off the top of my head,
so lemme think of one before I get into it.

> I basically want to create new tokens and new BNF elements which fit
> into the expression/statement part of the language and macro evaluate
> into other existing structures of the language. From what I know of
> lisp-reader-macros, this is sort of what they do.

Yeah; I forget where the Dylan macro proposals went, but they might be a
starting point.

My code follows.

Jay

------ First, the sugar

function begin_class(name)
   if _class_declaration then
      error("class "..name.." began before ".._class_declaration.name.."
ended")
   end
   _class_declaration = {name=name, table={}}
   -- to be really fastidious about namespace, swap stuff like add_slots_to
into globals() now
   -- if not, feel free to set the global "class" to this so the user
doesn't have to
   return _class_declaration.table
end

function add_slots_to(t)
   if getn(t) ~= 1 then
      error("add_slots_to must have one and only one numeric argument")
   end
   local target = t[1]
   for i,v in t do
      if i ~= 1 then
         -- if target[i] then error("redefinition of slot") end
         target[i] = v
      end
   end
end

function end_class(name)
   if not _class_declaration then
      error("end_class without a begin_class")
   end
   if _class_declaration.name ~= name then
      error("end_class of "..name.." but the class
".._class_declaration.name.." is open")
   end
   declare_class(name, _class_declaration.table)
   -- clean anything out of the global namespace that you put there
   return nil -- to empty out the "class" global
end

function call_me_before_main_loop()
  if _class_declaration then
    error("class declaration ".._class_declaration.name.." was never
closed!")
  end
end

--- Your code begins here

class = begin_class("MainShip")

add_slots_to{class;
   _parents = { air_physics, controllable, collidable },
   Condition = "Healthy",
   imgdir = 2.0,   -- the image index

   rimgdir = 1.0,
   direction = 0.0, -- in degrees
   bullet_type = "bullet",
   objtype = "mainship",
   exp_timer = 0.0,
   frame_time = 70,
   layer = 1,

   damage = 0,
   damage_max = 10,
   recharge_rate = 0.1,

   VisualRep = VisualReps.newDropShip
}

-- dummy ai_event
function class:ai_event()
end

function class:new(a_list) -- constructor
   if (type(a_list) ~= "table") then
      print("mainship:new() called with non-table "..tostring(a_list));
   else
      a_list._parents = { self };
      a_list.key = {}; -- make our private keydown list
      a_list.ctrl_centered = 1.0;
      a_list.dest_dir = 0.0;
   end
   return a_list
end

function class:recharge(byWhom) -- recharge method
   local damage = self.damage;
   if (damage > 0) then
      damage = max(0,damage - recharge_rate);
      self.damage = damage;
   end
end

class = end_class("MainShip")

-- [Time passes...]

call_me_before_main_loop()