I've added a prefix # operator to CLOX that converts its argument to a string, so that (for example) #123 produces "123". To implement it, I have:
Added native functions type, has, and str_ that return the name of an object's Lox-level type, check if an object has an attribute, and convert an object to a string (returning instance for instances).
Added a Lox standard library (borrowing the idea from Wren, I compile a small bit of Lox code as a prefix to the user's program).
Translated # expr into a call to str(expr), where str (without the trailing underscore) is part of the standard library:
fun str(obj) {
if ((type(obj) == "instance") and has(obj, "str")) {
return obj.str();
} else {
return str_(obj);
}
}
This implementation allows classes to define their own str methods, like the __str__ and __repr__ methods of Python.
I'd like to define an infix version of # that concatenates the string representations of objects so that print("hello: " # 123); prints "hello: 123". Like the prefix version, infix # should call each operand's str method if there is one, or use the built-in str_ as a fallback, and then concatenate the results.
So here's the problem: by the time the compiler reaches the infix #, it has already generated code for the left operand, but function calls expect name arg1 arg2 on the stack, not arg1 name arg2. One possibility is to add a second kind of CALL instruction that rearranges the top of the stack (or expects things in a different order, e.g., arg1 arg2 name), but I'm hoping there's a more elegant solution: adding a new VM instruction to support a single use case seems clumsy. Suggestions would be very welcome - thanks in advance.
I've added a prefix
#
operator to CLOX that converts its argument to a string, so that (for example)#123
produces"123"
. To implement it, I have:type
,has
, andstr_
that return the name of an object's Lox-level type, check if an object has an attribute, and convert an object to a string (returninginstance
for instances).# expr
into a call tostr(expr)
, wherestr
(without the trailing underscore) is part of the standard library:This implementation allows classes to define their own
str
methods, like the__str__
and__repr__
methods of Python.I'd like to define an infix version of
#
that concatenates the string representations of objects so thatprint("hello: " # 123);
prints"hello: 123"
. Like the prefix version, infix#
should call each operand'sstr
method if there is one, or use the built-instr_
as a fallback, and then concatenate the results.So here's the problem: by the time the compiler reaches the infix
#
, it has already generated code for the left operand, but function calls expectname arg1 arg2
on the stack, notarg1 name arg2
. One possibility is to add a second kind ofCALL
instruction that rearranges the top of the stack (or expects things in a different order, e.g.,arg1 arg2 name
), but I'm hoping there's a more elegant solution: adding a new VM instruction to support a single use case seems clumsy. Suggestions would be very welcome - thanks in advance.