PICO-8 Wiki
Advertisement

One of the stricter limits PICO-8 places on its carts' code is that they must contain no more than 8192 tokens.

A token is one of:

  • A literal value, such as nil, false, true, any number (e.g. 123, 0xff.ff, -3, ~1e4), or any string (of any size).
  • A variable or operator
  • An opening bracket ('(', '[', '{')
  • A keyword, with the exception of end and local

In particular, the following are not counted as tokens:

  • The comma (,), semicolon (;), period (.), colon (:), and double-colon (::)
  • Closing brackets (')', ']', '}')
  • The end and local keywords
  • The unary minus (-) and complement (~) operators when applied on a numeric literal

Token saving tips[]

Common token saving tips that apply to most situations:

  • Instead of assigning one variable per statement, combine assignments into a single statement, saving on the '=' token:

    a=1 b=2 c=3a,b,c = 1,2,3

    local a=1; local b=2local a,b = 1,2
  • Trailing nils can be omitted when assigning variables:

    mynum,myobj,myobj2 = 3,nil,nil -> mynum,myobj,myobj2 = 3

    local a,b = nil,nillocal a,b
    • Declaring a global with a value of nil at program start is equivalent to not declaring it at all. It is worth putting comments to keep track of these "undeclared" variables.
  • Usually trailing nils can be omitted when calling functions:

    f(a,b,nil,nil)f(a,b)

    Beware that some functions do check the number of arguments provided, and differ in behaviour between a nil and an unprovided argument.
  • When calling a function with only 1 argument, and that argument is a string or table literal, the parentheses can be omitted to save a token:

    f("smart")f "smart"

    f({1,2,3})f {1,2,3}
  • In many cases, nil can be used instead of false for boolean variables and parameters, allowing the use of other tricks in this list that allow omitting nil.

    f(a,b,false)f(a,b)

    local a,b = true, falselocal a,b = true

    Beware that while most operators and functions operating on booleans accept nil as false, a small few (like direct comparison via ==) can still break this approach.
  • When creating functions, move any parameters that may not need to be specified or that can have a good default value to the end of the parameter list, so that callers can usually avoid passing them.
  • Avoid defining constants or computing constants, preferring to use a single constant instead.

    hour=60*60; f(hour); g(hour)f(3600); g(3600)

    Beware that this can make changing those constants harder, so prefer to do it only once after being sure the constants won't change anymore.
  • Use a local variable to save the value of a computation that will be used again later, when doing so will save tokens. (The more complex the computation and the more it is repeated, the more likely that a local will save tokens)

    f(a+1); g(a+1); h(a+1)local ap1=a+1; f(ap1); g(ap1); h(ap1)

    f(a.x, a.x+1, a.x+5, a.x+10, a.x+12); g(a.x, -a.x)local ax=a.x; f(ax, ax+1, ax+5, ax+10, ax+12); g(ax, -ax)
  • For constant tables of numbers or strings, a string literal may be split() to save many tokens.

    t={1,2,3,10,9,8,99,-1}t=split "1,2,3,10,9,8,99,-1"
  • Use and and or instead of if when possible:

    if (f()) a=x else a=ya = f() and x or y (Beware: this only works if x can never be false or nil!)
  • Prefer member access over array indexing:

    tbl['special']tbl.special

    An object like {a=1,b=2,c=3} takes fewer tokens to read/write values from that {1,2,3}, though the latter takes fewer tokens to construct. This is usually beneficial as objects usually need to be accessed in multiple places but only need to be constructed in one function.
  • Make use of API default arguments, especially with math calls where they default to 0:

    x=max(x,0); y=min(y,0); z=mid(z,0,1)x=max(x); y=min(y); z=mid(z,1)
  • The \ operator lets you divide and floor at the same time.
    flr(a/10) is equivalent to a\10
    

Miscellaneous token saving tips for specific situations:

  • It is possible to save 1 token by converting pairs(mytable) to next, mytable (which is equivalent, with the minor exception that pairs() calls the __pairs() metamethod if one is implemented in mytable)
  • Similarly, 1 token can be saved by converting ipairs(mytable) to inext, mytable
Advertisement