Discussions in support of the LOLCODE.com wiki
You are not logged in.
So I was hoping to more formally define some LOLCode/Java interaction. It's my goal to get LOLCode to compile to byte-code and interact with Java as if it were a class (ala groovy). I know Brett Kail has done some good work so far with a Java Module for LOLCode so i was going to start off with his LOLCode interface to Java as a starting point and work on a Java ineterface to LOLCode.
bjkail wrote:
Module: JAVA
------------
+ Usage
- This module introduces a new expression:
JAVA <expression>
The expression operand is implicitly cast to YARN, and the result is passed
to Class.forName. If the class cannot be found, BadJavaClass is thrown.
The result of the expression is a JAVA value.
+ JAVA value
- JAVA values wrap a Java object, which includes arrays and Class objects.
JAVA values can be implicitly cast to YARN, which returns the result of
calling toString() on the underlying object. Attempting to cast a JAVA
value to TROOF, NUMBR, or NUMBAR results in BadJavaUse.
- Fields and methods of the underlying object can be accessed by using BUKKIT
slot syntax. Fields cannot be declared. When setting a field or passing
method arguments, LOLCODE values are converted to Java values (see "LOLCODE
to Java conversion"). When a field value or method value is returned, Java
values are converted to LOLCODE values (see "Java to LOLCode conversion").
- If a method slot is found but none of the methods have the appropriate
number of arguments, BadArgumentCount is thrown. If a method slot is found
but none of the methods can be called because an argument fails to be
converted, then BadJavaType is thrown.
- If an exception is thrown while executing a method, the type of the
exception for an O NOES clause is the class name of the exception.
- If a JAVA value represents a Class, then only static members of the class
can be accessed. Otherwise, both static and non-static members of the
object's class can be accessed.
- If a value represents a class, a slot named "new" is available.
- If the class is an array, then the slot may be called with a single
argument that is implicitly cast to NUMBR that specifies the size of the
array.
- Otherwise, the slot may be called, and a constructor is selected using
the same algorithm as method slots.
- If a value represents an array
- Numerical indices can be used. If the index is out of bounds, then
BadSlot is thrown.
- A slot named "length" is available that returns the length of the array.
- Attempting to assign a method slot, the "new" slot of a class, or the
"length" slot of an array, then BadSlot is thrown.
+ LOLCODE to Java conversion
- If the value is NOOB, it is converted to null. If the target type is a
primitive type, BadJavaType is thrown.
- If the value is JAVA, it is unwrapped. If the target type is
incompatible, BadJavaType is thrown.
- boolean, Boolean - implicit cast to TROOF
- byte, Byte, short, Short, char, Character, int, Integer, long, Long -
implicit cast to NUMBR
- float, Float, double, Double - implicit cast to NUMBR
- String - implicit cast to YARN
- Object
- TROOF - Boolean
- NUMBR - Integer
- NUMBAR - Float
- YARN - String
- BadJavaType is thrown.
+ Java to LOLCODE conversion
- null - NOOB
- Long, Double, String - YARN
- Float - NUMBAR
- Number - NUMBR
- All other values are converted as a JAVA value
So... we have the following convention "primitive" convention
Java LOLCode
----------------------------------
null <-> NOOB
Long -> YARN (I'd prefer Numbr)
Double -> YARN (I'd prefer Numbar)
String <-> YARN
Float <-> NUMBAR
Number <-> NUMBR
Integer <-> NUMBR
Next... How does a LOLCode file compile to interact with java?
I'd like to see the following:
Cheezburger.lol
HAI
I HAS A name ITZ "class"
O HAI IM Cheezburger
I HAS A name ITZ "instance"
HOW DUZ I foo YR bar?
FOUND YR SMOOSH bar AN "-extra" MKAY
IF U SAY SO
KTHX
KTHXBYETest.java
import Cheezburger;
import junit.*;
import static junit.assert.*;
public class Test {
@Test
public tryJavaInteract() {
//Global variable map as class statics
assertEquals("class", Cheezburger.name());
//Classes map as classes, if filenames line up, otherwise they become nested inner-classes
Cheezburger b = new Cheezburger();
//Property slots map to getters/setters
assertEquals("instance", b.getName());
//Method slots map as real methods. Classes pass through
assertEquals("test-extra", b.foo("extra"));
}
}Ok, now as for access Java from lolcode...
Widget.java
public class Widget {
private int id;
private Point location;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public void someMethod(String arg1, Integer arg2) { ... }
....
}Test.lol
HAI CAN HAS Widget? BTW Uses some classloaderish mechanism to pull in a .class file. LOLCode impl needs to do some magic to make this work. I HAS A w ITZ A Widget BTW "prototypes" the class. BTW Java beans props map to slots... private/public constraints enforced at runtime and throw exception w-id R 5 VISIBLE w!!id BTW 5 BTW Function call syntax w someMethod YR "Yarn" AN YR w-id MKAY KTHXBYE
Offline
Has anyone read the JSR 223 Spec? That's basically what I'm pushing for...
Offline
JoshSuereth wrote:
So... we have the following convention "primitive" convention
Java LOLCode
----------------------------------
null <-> NOOB
Long -> YARN (I'd prefer Numbr)
Double -> YARN (I'd prefer Numbar)
String <-> YARN
Float <-> NUMBAR
Number <-> NUMBR
Integer <-> NUMBR
I wanted the conversions to be lossless. Since long-to-int and double-to-float are truncating operations, I decided to convert to YARN. Long.valueOf(String).intValue() is one way to convert. A better option would probably have been to just return Long and Double objects.
JoshSuereth wrote:
Next... How does a LOLCode file compile to interact with java?
I started thinking about this, and coming up with a nice ABI was the challenging part.
JoshSuereth wrote:
Has anyone read the JSR 223 Spec? That's basically what I'm pushing for...
I haven't read the spec, but I have read through the javax.script javadoc. I didn't finish implementing, so it ended up as a TODO in the README.
Offline
I understand not wanting to lose precision. I was thinking of making the LOLtypes just be larger... i.e. Numbar <-> Double, Numbr <-> Long.
Yeah... the ABI would be hard to do. Especially with bukkits having prototype OO.
I was thinking of a groovy solution:
Every .lol file compiles to a .class file.
Variable definitions (I HAS A) turn into static variables.
Function definitions (HOW DUZ I) turn into static methods.
General statments get placed on the <clinit> block of the class.
// For 1.3 Bukkit spec as it exists now....
Bukkits turn into "nested" class files
Variables on bukkit turn into instance variables
Functions on bukkit turn into instance variables
Instances of bukkit created turn into dynamic proxies. These first check for any "new" slots added to a bukkit before delegating to existing "compiled" functions.
There's a LOT left unsaid, but this was the first approach I sort of came by. We need a way of defining a function and delegating to it at runtime, and still having it find things on the scope appropriately (using LOLCode rules not Java). I'm thinking there needs to be some sort of "Runtime" object (can be thread-local) that's used to look up variables. If this function fails, then we attempt to access a "local" property and fail.
K... it's late so I may be repeating myself or not making sense anymore. Let me know what you think.
Offline
Let me know what you think of this for syntax within java to call LOLCode...
This assumed that you have a "MyLOLFile.lol" that has been compiled to "MyLOLFile.class" and added to the path.
import MyLOLFile;
import com.lolcode.core; // This is where all the abstract LOL interfaces exist for java to access 'live" LOL variables.
public static void main...blah..blah..blah {
//Accessing a variable
MyLOLFile.get("variablename");
MyLOLFile.getVariablename(); //if available statically
MyLOLFile.set("variablename", "value");
MyLOLFile.setVariablename("value"); //if available statically
//Access a function...
MyLOLFile.fooin("value");
//Access a random Bukkit from the .lol file
Bukkit obj = new MyLOLFile.TestBukkit();
//IF the bukkit has the same name as the lol file
obj = new MyLOLFile();
//Invoking bukkit functions
obj.invoke("fooin", "value");
obj.invoke("fooin", new Object[] {"value"});
((MyLOLFile)obj).fooin("value"); //If fooin is defined within the MyLOLFile.lol, otherwise it's not available statically.
// Accessing slots
obj.get("slotname");
obj.set("slotname", "value");
obj.getSlotname(); // if available statically
obj.setSlotname("value"); //if available statically
}The getters/setters take POJOs (which LOLcode then casts). I'm thinking LOLCode might have to interact directly with Strings, Doubles, Longs and Booleans. Basically for the ABI I was going to use the Java .class file format for maximum Java-LOL integration. The problem there is we'd have to do some nifty hack to get the apropriate runtime behavior for LOL classes.
Offline
Assuming your interpreter is itself written in Java, whatever syntax you use can be equivalent to the way the interpreter itself works.
Offline
Coda wrote:
Assuming your interpreter is itself written in Java, whatever syntax you use can be equivalent to the way the interpreter itself works.
This is no more "interpreter" really. Things compile down to java byte-code in a .class file, and you can use regular java semantics to load/run LOLCode programs. You should read above.
Offline