Inline Native, Native Properties, and Macro Methods

I've made a couple of additional improvements to Rogue's native support.

First I came up with an even better way to inline native code. You write
native("...")->Type (the return type and parentheses are optional)
and the compiler not only throws the string into the output C++ code with
$marker replacement, it also knows what type of value the native expression results in, allowing native expressions to interoperate easily with other Rogue code.

For example, here's a method that would return the system time in seconds for a version of Rogue that targeted Java:

class Time
  ROUTINE
    routine current->Real
      return native( "System.currentTimeMillis()" )->Long / 1000.0
endClass

This would produce the following line of Java code:

return System.currentTimeMillis() / 1000.0;

The only minor problem is that this form of inline native (native code defined in line) is ambiguous with my inlineNative keyword (native code defined separately that is inserted inline). I've consequently changed my existing inline and inlineNative keywords to be macro and macro native instead.

As an example of how things stand, here's a test class that produces the same line of code four times in four different ways:

# Test.rogue
Test()

class Test
  METHODS
    method init
      local x = 5
      print_test( x, x+1 )
      print_test( x, native("($x + 1)")->Integer )
      print_test( x, inline_plus_1(x) )
      print_test( x, inline_native_plus_1(x) )

    method print_test( a:Integer, b:Integer )
      println "$ + 1 is $" (a,b)

    method inline_plus_1( x:Integer )->Integer
      macro x+1

    method inline_native_plus_1( x:Integer )->Integer
      macro native "($x + 1)"
endClass


# Output (roguec Test.rogue --execute)
5 + 1 is 6
5 + 1 is 6
5 + 1 is 6
5 + 1 is 6


# Test.init() in Test.cpp
RogueClassTest* RogueTest__init( RogueClassTest* THIS )
{
  RogueInteger x_0 = (5);
  RogueTest__print_test( THIS, x_0, (x_0 + 1) );
  RogueTest__print_test( THIS, x_0, (x_0 + 1) );
  RogueTest__print_test( THIS, x_0, (x_0 + 1) );
  RogueTest__print_test( THIS, x_0, (x_0 + 1) );
  return (RogueClassTest*)(THIS);
}

The second new native feature is the ability to add native properties to objects. These are really the simplest possible thing: just strings that get stuck into the class definition on the native side. But they allow Rogue-side objects to have C++ properties. For example, here's my revamped FileReader class. It used to be a [native] class with a bunch of [native] methods that mapped to a hard-coded definition in my C++ library, but now it's all defined Rogue-side:

class FileReader : Reader<<Character>>
  PROPERTIES
    filepath        : String
    buffer_count    : Integer
    buffer_position : Integer
    count           : Integer
    position        : Integer
    native "FILE* fp;"
    native "unsigned char buffer[1024];"

  METHODS
    method init( _filepath:String )
      open( _filepath )

    method close->this
      native @|if ($this->fp)
              |{
              |  fclose( $this->fp );
              |  $this->fp = 0;
              |}

      position = 0
      count = 0
      return this

    method has_another->Logical
      return (position < count)

    method open( filepath )->Logical
      close

      native @|char path[ PATH_MAX ];
              |$filepath->to_c_string( path, PATH_MAX );
              |
              |$this->fp = fopen( path, "rb" );
              |if ($this->fp)
              |{
              |  fseek( $this->fp, 0, SEEK_END );
              |  $count = (RogueInteger) ftell( $this->fp );
              |  fseek( $this->fp, 0, SEEK_SET );
              |}

      # Always close after the last byte is read
      if (count == 0) close
      
      return (position < count)

    method peek->Character
      if (position == count) return 0

      if (buffer_position == buffer_count)
        native @|$buffer_count = (RogueInteger) fread( $this->buffer, 1, sizeof($this->buffer), $this->fp );
        buffer_position = 0
      endIf

      native @|return $this->buffer[ $buffer_position ];

    method read->Character
      if (position == count) return 0

      local result = peek

      ++position
      ++buffer_position
      if (position == count) close

      return result

    method remaining->Integer
      return count - position

    method set_position( @position )->this
      native @|if ($this->fp)
              |{
              |  fseek( $this->fp, $position, SEEK_SET );
              |}

      buffer_position = 0
      buffer_count = 0
      return this
endClass