Log In  


I just came across moonscript the other day. It's a sort of coffeescript-esque language that compiles to Lua. It has a lot of nifty features -- including arrow functions, which is what sold me.

So I wrote a tool that allows you to watch a .moon file and pipe it into the lua part of a .p8 cartridge. It's not thoroughly test and probably only works on OS X, but I've been personally enjoying writing moonscript in Sublime Text 3 and watching PICO-8 automatically reload on save :)

I'll drop the link here in case anyone finds it useful or intriguing: PICOMOON

Cheers!

7


As a JavaScript programmer for the past 15+ years, I'd really like to see something like this for js, as I definitely prefer C-style syntax personally (and it's definitely easier to write more compact code in js than in Lua, due to Lua's syntax verbosity). I mean, all programming languages are extremely similar anyway (I have experience with JS, PHP, classic ASP (VBScript), BASIC, C#, Java, Delphi, Ruby, Python, ActionScript, and now Lua - they're all pretty much the same), it just all comes down to preference.

Moonscript doesn't seem like something I'd personally be interested in due to my preference for C syntax (I also don't have OSX to test your program with), but it's interesting nonetheless to see people making P8 compilers for other languages.


So I looked around and there are plenty of Lua to JS transpilers. Looks like slim pickins the other way around.

I did find one option that would probably work for ES5 to Lua. So you wouldn't have any sexy ES2015+ features. But if you're into it, I can work on adding the option to picomoon! Should be pretty straightforward.


Yeah man, like I said on Twitter, that would be excellent! Not that worried about being able to do ES6, so don't sweat that. It's kinda funny because if you use the HTML5 exporter, it transcodes the Lua into JS (well, sort-of... more of an encoding that's decoded by JS, but still). So it's kinda like making your game in JS, then converting it to Lua, then back to JS again - doesn't get much more meta than that :P


You're so right about that meta aspect of this! I'm hoping in the future, we can get more options to integrate with the JS ecosystem. But until then...here's what I've been playing around with.

On the command line (be sure you npm i -g castl first):

picomoon -l js js2p8.js

In js2p8.js:

function _init() {
  player = new circle(7, 8, 64, 64);
}

function _update() {
  if (btn(0)) player.position.x--;
  if (btn(1)) player.position.x++;
  if (btn(2)) player.position.y--;
  if (btn(3)) player.position.y++;
}

function _draw() {
  cls();
  rectfill(0,0,127,127,5);
  player.draw();
  console.log('yay!');
}

/**
 * classes - 
 * ...sort of
 * since we don't have metatables,
 * custom objects can't really have a prototype
 * until you explicitly create one
 */

function vector(x, y) {
  this.x = x;
  this.y = y;
}
vector.prototype = {
  toarray: function() {
    return [this.x, this.y];
  }
};

function circle(radius, color, x, y) {
  this.radius = radius;
  this.color = color;
  this.position = new vector(x, y);
}
circle.prototype = {
  draw: function() {
    circfill(
      this.position.x,
      this.position.y,
      this.radius,
      this.color
    );
  }
};

/*
 * the console object
 */
// print() - log, info, warn, error
console.log('prints in pico-8')
// printh() - debug
console.debug('prints on the command line')

/*
 * nil values -
 * these all just compile to nil for now
 */
var a = null;
var b = NaN;
var c = undefined;

/**
 * arrays -
 * 0-indexed arrays with all the built-in methods
 * I haven't tested them throughly, so there may be bugs here
 * would love to know if you encounter any issues:
 * https://github.com/jozanza/picomoon/issues
 */
var d = [1,2,3];
var e = c[2];
var f = d.map(function (x) {
  return x * 2
});

/**
 * type coercions -
 * weird JS stuff
 */
var g = '' + d + a + ''
var h = +'3'

1

wouldn't it be even better if pico8 supported moonscript right off the bat ?
Since moonscript was designed to be converted into lua and there is a lua at the beginning of each .p8 file, we should be able to change that header by a moonscript header.
The point is that moonscript has classes and require less characters to write code.


that would be very cool. i guess LUA is more popular than moonscript?

how about a swift header then?


well moonscript was designed to compile into lua, which is not the case for swift. However i still don't understand why lua was chosen in the first place.
But now that there is a lot of games and programs made for pico-8 in lua, we cannot drop it for backward compatibility :/


Lua was probably chosen because it's a script language made for being embedded into application, unlike all of that things like moonscript, cofeescript and all of that JS thingy.

Translating a language into another is something I never understood...


well moonscript was designed to be translated into lua. So like lua, it was made to be embedded into application (moonscript has nothing to do with JS).


1

I still think it would be wise to implement moonscript directly into pico-8
moonscript can be compiled into lua, using lua itself,
it already implement some pico-8 shorthand such as += -= *= ...
and most lua keywords are replaced by symbols which take less characters to write which would be useful to code in pico-8 since we are limited at 32 characters per line visible at once.
for example "function" is replaced by "->", "self" by "@"
whereas keywords like "then","do","end","local","return" are ommited

here an example of how I would implement a vector class for both language:
(the lines show the width of the screen in pico-8)

-- lua -------------------------

function copy(o)
 local c
 if type(o)=='table' then
  c={}
  for k,v in pairs(o) do
   c[k]=copy(v)
  end
 else c=o end
 return c
end

-- vector class --
vec={x=0,y=0}
--set coords of vector
function vec:set(x,y)
 self.x=x
 self.y=y
 return self
end
--are vectors equal ?
function vec:equ(v)
 return self.x==v.x
 and    self.y==v.y
end
--add vector
function vec:add(v)
 self.x+=v.x
 self.y+=v.y
 return self
end
--multiply by scalar
function vec:mul(n)
 self.x*=n
 self.y*=n
 return self
end
--lenght of vector
function vec:len()
 return sqrt(
  self.x*self.x+self.y*self.y)
end

-- moonscript ------------------

class vec
 --constructor
 new:=>
  @x=0
  @y=0
 --setter
 set:(x,y)=>
  @x=x
  @y=y
  @
 --are vectors equal ?
 equ:(v)=>
  @x==v.x and @y==v.y
 --add vector
 add:(v)=>
  @x+=v.x
  @y+=v.y
  @
 --multiply by scalar
 mult:(n)=>
  @x*=n
  @y*=n
  @
 --lenght of vector
 len:()=>
  sqrt @x*@x+@y+@y

The only negative aspect of moonscript is that it's a little more cryptic to read and we would have to add an option to switch between both language.


So @ is this/self? Neat. I always wanted C++ to do 'this' and members/methods differently. @ is one of the options I considered, though I actually settled on this:

void Object::SetPosition(int x, int y)
{
    .x = x;
    .y = y;
}

Alas, Bjarne doesn't listen to me and we still have the same old mess. :)


@harraps you missed :equ in the moonscript version.

I like how much more succinct moonscript is, though.

If moonscript was added to P8 would it be the only way to code? Or would it be optional?

If it was the only way, P8 becomes more niche due to the fact that less people know moonscript, and that moonscript is less obvious than LUA.

If it was optional, P8 support fractures into two code styles. Would somebody who writes pure P8/LUA be willing to help a moonscript user?

Zep has said originally P8 used a BASIC variation, but LUA won out:

Though PICO-8 initially ran BASIC to stay true to its ‘80s pedigree, White switched because “Lua has a small footprint and is portable and quite fast. I think any language could have worked though, as long as it allowed the user to mess about in an unstructured way without worrying about programming style.

https://www.pastemagazine.com/articles/2016/01/the-modest-fantasy-of-the-pico-8.html



@matt Obviously it would have to be optional,
again you cannot get rid of the support for thousand of games and programs made in lua for pico-8 like that.
And again moonscript is based on lua, so you can use lua functions in moonscript (the syntax change but not the effect)
So a lua user can help a moonscript user because the functions are the same, not the syntax.
Again i think it would be interesting to add a functionality to code in moonscript rather than lua even if it means that one have to mess with the .p8 file to do so.

Otherwise I think we should have more shorthands for common keywords like "then", "end", "function", "or", "and", "not" which takes a lot of space in codes.


@harraps:

Well, they take space in source code, yes. They'd be the same number of tokens regardless. But I agree it'd be nice to have shorthand for things like FUNCTION, which use up a quarter of the screen width all by themselves. FN, maybe.

I think Lua's formatting actually ends up kind of nice in a proper setting, most of the time, but on this small screen it really doesn't want to be so verbose.

Like most programmers, I've always wanted to make my own language. Most languages are either too terse or not terse enough. Lua's on the not-enough side.

Consider this AI script that I lifted from Overwatch and applied some conceptual changes to, which I'm pretty certain could be parsed deterministically in tandem with the existing PICO-8 Lua rules:

FN TORBJORN:UPDATE()
  IF (.EQUIPPED==GUN)
    .EQUIPPED=HAMMER
  OR (.TURRET==NIL)
    .TURRET=NEW_TURRET()
  OR (NOT .FIGHTING)
    :HIT(.TURRET)
  OR (NOT .DAMAGED)
    :HIT(.TURRET)
  OR (#.TEAM.ALIVE==1)
    :ULTIMATE()
    :HIT(.TURRET)
  OR (MATCH.WINNER==.TEAM)
    :HIT(.TURRET)
  ELSE
    :HIT(.TURRET)
  END
END

That fits and reads so much better... I would especially like to swap OR in for ELSEIF. It's so much less klunky. I know none of it's going to happen, I'm just sort of daydreaming here.

I know this stuff is all syntactic sugar, but sometimes I just hate what a mess source code can be. Think of all the cleaner ways it could be laid out...

We could omit SELF since nothing else starts with :<alpha> or .<alpha>.

We could reduce keyword lengths.

We could extend the paren-style one-line IF() extension from PICO-8 to say that, when there's no actual code on the same line, it's inferred as if it were IF..THEN instead. I think the parser could probably even manage it without the parens, but I don't want to assume that.

There's just so much...

Ah well, I can dream.


@Felice

you cannot use "or" for "elseif" because "or" is already an operator like "and"
instead I would suggest "ef" or "<>"
for "function" we could use "=>"
for "then", "->"
for "return", "*>"
for "and", "&"
for "or", "|"
and for "end", "\"

=> dostuff(a,b)
  if a & b ->
    print("yes")
  ef a | b ->
    print("maybe")
  else
    print("no")
  \
  *> 10
\

@harraps:

Actually, 'OR' isn't an operator in that context. "OR" isn't an operator until there's already a left-hand value; it can't start an expression. Edit: I suppose if you have wrapping from the previous line, and the previous line ended with an expression it could conflict, hmm.

BTW the current version of Lua actually defines & and | as bitwise operators. We don't have these in PICO-8 Lua, sadly (zep? can we?), but it might be a bad idea to promote a habit among budding programmers that would conflict with usage in real Lua. You'd probably want to use the C++-style '&&' and '||' for logical operators if you were going to use symbols instead of words.



[Please log in to post a comment]