Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code (especially stack) too complex #1

Open
SoniEx2 opened this issue May 1, 2015 · 4 comments
Open

Code (especially stack) too complex #1

SoniEx2 opened this issue May 1, 2015 · 4 comments
Assignees

Comments

@SoniEx2
Copy link

SoniEx2 commented May 1, 2015

See https://github.com/SoniEx2/Stuff/tree/master/lua/Forth for a much simpler stack, exploiting language features (the call stack and the varargs)

(I'd think varargs are more efficiently JITted, idk)

@IonoclastBrigham
Copy link
Owner

Point taken. Much of the extant Lua code is actually going to be refactored or totally axed, as the project matures, and code generation will be rebuilt basically from scratch.

To your point on the stack, it's complex for how we'd normally think of a stack ADT class, but it actually is a very straightforward reproduction of the Forth-style stack manipulation routines, which is what I wanted when I was bootstrapping the project. One thing I definitely will be doing is to move most of those definitions into :Firth land, built from lower level primitives.

I'm not sure how varargs are actually implemented in LuaJIT. Arguments in general act like local variables, and local variables are very, very fast; they often end up in CPU registers, if the optimizer doesn't elide them completely.

Research references:
https://github.com/SoniEx2/Stuff/tree/master/lua/Forth
http://angg.twu.net/miniforth-article.html

@SoniEx2
Copy link
Author

SoniEx2 commented May 2, 2015

The varargs have the same semantics as a stack, when combined with select() and recursive calls. Combined with coroutines they give you a very simple stack implementation:

local function Stack(x, v, ...)
  if x == "push" then
    local nx, nv = coroutine.yield()
    return Stack(nx, nv, v, ...)
  elseif x == "pop" then
    local nx, nv = coroutine.yield((...))
    return Stack(nx, nv, select(2, ...))
  elseif x == "peek" then
    local nx, nv = coroutine.yield((...))
    return Stack(nx, nv, ...)
  end
  local nx, nv = coroutine.yield() -- or error()? altho that'd kill the stack, essentially deleting all values
  return Stack(nx, nv, ...)
end

function makestack(...)
  local stack = coroutine.wrap(Stack)
  stack(nil, nil, ...)
  return stack
end

-- push wish stack("push", v)
-- pop with v = stack("pop")

The Lua call stack has the same semantics as the Forth return stack, when used like this: https://github.com/SoniEx2/Stuff/blob/master/lua/Forth/Words.lua#L108-L187 (I use the "data stack" (varargs) when manipulating it, but properly written code never sees that - the spec only says accessing stuff you didn't push and pushing stuff without popping = undefined (or rather forbidden, but that's basically the same thing))

Idk, just wanted to talk about how you can (ab)use language features like this...

@IonoclastBrigham
Copy link
Owner

I was actually thinking about doing something like this, but I was having trouble wrapping my head around how to implement it cleanly. It didn't occur to me that coroutines would help here. Obvious, in retrospect.

To get the system up and running, I did it more like an ADT class, which I'm much more familiar with. I'll definitely study what you've done, and see if/how I can adapt the approach to my code, and vice-versa.

@IonoclastBrigham
Copy link
Owner

Outline for plans to refactor firth: http://blog.ionoclast.com/2015/05/the-future-of-firth-pre-alpha2-and-beyond/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants