Modified lexing strategy for keywords

Now using lookup table for all opcodes and keywords.
Tokens are stored as bitfields in nums, this does mean tokens need
to be checked for validity, but opcodes only need to be looked up once.

Currently the table is just generated at runtime, may
compile it by hand in the future.
Modified lexer to make assignments somewhat special

Any binary operator can be combined with an assignment like so.
    a += 10
    a ||= 10
    a /= 2

assignments have higher precedence then any operators
    (a + b).c += 10 ** 5-2
      <=>
    ((a + b).c) += (10 ** (5-2))
Modified op state handling

Made the opstate fit into an int. The should reduce the pressure on
the stack by a factor of 2. Since operator parsing is the only thing to
really use the stack that much, this is somewhat important.

Additionally fixed bug where parenthesis did nothing.
Added basic control flow

Unfortunately, the current strategy for code generation requires
that jump opcodes do not change size based on argument. No
jumps greater than 16 bits are generated.
Changed `nil` to a literal and added `if` primary

Rather than introducing ternary operators, if
statments can be used in primary expressions.
    let a = if (b) c else d

This can be extended to other expressions
    let a = while(c) next()
    let b = for(i : 0..100) i ** 2

There are some odd definitions such as an `if` with no `else`.
    let a = if(b) c

For lack of better implementation, this is defined to assign nil
if b is false. This requires the virtual machine to handle nil values,
which can't be stored in the table of constants. A simple solution was
to add the opcode `VNIL`, which simply puts `nil` on the stack. After
this addition there is no reason to make `nil` a keyword.

This doesn't sit very well with me, but there is currently no reason
to change the nil keyword.