mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 22:28:45 +01:00
Get rid of my name from TODOs. Anyone can do them.
This commit is contained in:
@ -30,14 +30,14 @@ class NthToggle {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(bob): The follow the other examples, we should be using inheritance
|
||||
// here. Since Wren doesn't currently support inherited fields or calling
|
||||
// superclass constructors, it doesn't. It probably won't make a huge perf
|
||||
// difference, but it should be fixed when possible to be:
|
||||
// TODO: The follow the other examples, we should be using inheritance here.
|
||||
// Since Wren doesn't currently support inherited fields or calling superclass
|
||||
// constructors, it doesn't. It probably won't make a huge perf difference,
|
||||
// but it should be fixed when possible to be:
|
||||
/*
|
||||
class NthToggle is Toggle {
|
||||
this new(startState, maxCounter) {
|
||||
// TODO(bob): Need to distinguish superclass method calls from superclass
|
||||
// TODO: Need to distinguish superclass method calls from superclass
|
||||
// constructor calls.
|
||||
super.new(startState)
|
||||
_countMax = maxCounter
|
||||
|
||||
@ -34,7 +34,7 @@ void wrenFreeVM(WrenVM* vm);
|
||||
|
||||
// Runs [source], a string of Wren source code in a new fiber in [vm]. Returns
|
||||
// zero if successful.
|
||||
// TODO(bob): Define error codes.
|
||||
// TODO: Define error codes.
|
||||
int wrenInterpret(WrenVM* vm, const char* source);
|
||||
|
||||
#endif
|
||||
|
||||
9
metrics
9
metrics
@ -1,10 +1,12 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import glob
|
||||
import fnmatch
|
||||
import itertools
|
||||
import os
|
||||
import re
|
||||
|
||||
TODO_PATTERN = re.compile(r'\s*// TODO\(')
|
||||
TODO_PATTERN = re.compile(r'\s*// TODO:')
|
||||
DOC_PATTERN = re.compile(r'\s*//')
|
||||
EXPECT_PATTERN = re.compile(r'// expect')
|
||||
|
||||
@ -42,9 +44,10 @@ for source_path in files:
|
||||
|
||||
num_code += 1
|
||||
|
||||
for test_path in glob.iglob("test/*.wren"):
|
||||
for dir_path, dir_names, file_names in os.walk("test"):
|
||||
for file_name in fnmatch.filter(file_names, "*.wren"):
|
||||
num_test_files += 1
|
||||
with open(test_path, "r") as input:
|
||||
with open(os.path.join(dir_path, file_name), "r") as input:
|
||||
for line in input:
|
||||
if (line.strip() == ""):
|
||||
num_test_empty += 1
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
// This is the source file for the standalone command line interpreter. It is
|
||||
// not needed if you are embedding Wren in an application.
|
||||
|
||||
// TODO(bob): Don't hardcode this.
|
||||
// TODO: Don't hardcode this.
|
||||
#define MAX_LINE 1024
|
||||
|
||||
static void failIf(int condition, int exitCode, const char* format, ...)
|
||||
@ -76,9 +76,9 @@ static int runRepl()
|
||||
char line[MAX_LINE];
|
||||
fgets(line, MAX_LINE, stdin);
|
||||
|
||||
// TODO(bob): Handle failure.
|
||||
// TODO: Handle failure.
|
||||
wrenInterpret(vm, line);
|
||||
// TODO(bob): Figure out how this should work with wren API.
|
||||
// TODO: Figure out how this should work with wren API.
|
||||
/*
|
||||
ObjFn* fn = compile(vm, line);
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#ifndef wren_common_h
|
||||
#define wren_common_h
|
||||
|
||||
// TODO(bob): Use stdbool.h and `bool` for bools instead of int/1/0.
|
||||
// TODO: Use stdbool.h and `bool` for bools instead of int/1/0.
|
||||
|
||||
// This header contains macros and defines used across the entire Wren
|
||||
// implementation. In particular, it contains "configuration" defines that
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
// extra spaces added to handle arity, and another byte to terminate the string.
|
||||
#define MAX_METHOD_SIGNATURE (MAX_METHOD_NAME + MAX_PARAMETERS + 1)
|
||||
|
||||
// TODO(bob): Get rid of this and use a growable buffer.
|
||||
// TODO: Get rid of this and use a growable buffer.
|
||||
#define MAX_STRING (1024)
|
||||
|
||||
typedef enum
|
||||
@ -137,7 +137,7 @@ typedef struct
|
||||
// Non-zero if a syntax or compile error has occurred.
|
||||
int hasError;
|
||||
|
||||
// TODO(bob): Dynamically allocate this.
|
||||
// TODO: Dynamically allocate this.
|
||||
// A buffer for the unescaped text of the current token if it's a string
|
||||
// literal. Unlike the raw token, this will have escape sequences translated
|
||||
// to their literal equivalent.
|
||||
@ -211,9 +211,9 @@ typedef struct sCompiler
|
||||
// Adds [constant] to the constant pool and returns its index.
|
||||
static int addConstant(Compiler* compiler, Value constant)
|
||||
{
|
||||
// TODO(bob): Look for existing equal constant. Note that we need to *not*
|
||||
// do that for the placeholder constant created for super calls.
|
||||
// TODO(bob): Check for overflow.
|
||||
// TODO: Look for existing equal constant. Note that we need to *not* do that
|
||||
// for the placeholder constant created for super calls.
|
||||
// TODO: Check for overflow.
|
||||
compiler->fn->constants[compiler->fn->numConstants++] = constant;
|
||||
return compiler->fn->numConstants - 1;
|
||||
}
|
||||
@ -361,7 +361,7 @@ static void skipBlockComment(Parser* parser)
|
||||
int nesting = 1;
|
||||
while (nesting > 0)
|
||||
{
|
||||
// TODO(bob): Unterminated comment. Should return error.
|
||||
// TODO: Unterminated comment. Should return error.
|
||||
if (peekChar(parser) == '\0') return;
|
||||
|
||||
if (peekChar(parser) == '/' && peekNextChar(parser) == '*')
|
||||
@ -397,7 +397,7 @@ static int isKeyword(Parser* parser, const char* keyword)
|
||||
// Finishes lexing a number literal.
|
||||
static void readNumber(Parser* parser)
|
||||
{
|
||||
// TODO(bob): Hex, scientific, etc.
|
||||
// TODO: Hex, scientific, etc.
|
||||
while (isDigit(peekChar(parser))) nextChar(parser);
|
||||
|
||||
// See if it has a floating point. Make sure there is a digit after the "."
|
||||
@ -461,11 +461,11 @@ static void readString(Parser* parser)
|
||||
case 'n': addStringChar(parser, '\n'); break;
|
||||
case 't': addStringChar(parser, '\t'); break;
|
||||
default:
|
||||
// TODO(bob): Emit error token.
|
||||
// TODO: Emit error token.
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(bob): Other escapes (\r, etc.), Unicode escape sequences.
|
||||
// TODO: Other escapes (\r, etc.), Unicode escape sequences.
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -576,7 +576,7 @@ static void readRawToken(Parser* parser)
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO(bob): Handle error.
|
||||
// TODO: Handle error.
|
||||
makeToken(parser, TOKEN_ERROR);
|
||||
}
|
||||
return;
|
||||
@ -967,7 +967,7 @@ static void endCompiler(Compiler* compiler, int constant)
|
||||
|
||||
// Emit arguments for each upvalue to know whether to capture a local or
|
||||
// an upvalue.
|
||||
// TODO(bob): Do something more efficient here?
|
||||
// TODO: Do something more efficient here?
|
||||
for (int i = 0; i < compiler->fn->numUpvalues; i++)
|
||||
{
|
||||
emit(compiler->parent, compiler->upvalues[i].isLocal);
|
||||
@ -1068,7 +1068,7 @@ static void parameterList(Compiler* compiler, char* name, int* length)
|
||||
|
||||
// Add a space in the name for the parameter.
|
||||
if (name != NULL) name[(*length)++] = ' ';
|
||||
// TODO(bob): Check for length overflow.
|
||||
// TODO: Check for length overflow.
|
||||
}
|
||||
while (match(compiler, TOKEN_COMMA));
|
||||
consume(compiler, TOKEN_RIGHT_PAREN, "Expect ')' after parameters.");
|
||||
@ -1083,7 +1083,7 @@ static void namedCall(Compiler* compiler, int allowAssignment, Code instruction)
|
||||
char name[MAX_METHOD_SIGNATURE];
|
||||
int length = copyName(compiler, name);
|
||||
|
||||
// TODO(bob): Check for "=" here and set assignment and return.
|
||||
// TODO: Check for "=" here and set assignment and return.
|
||||
|
||||
// Parse the argument list, if any.
|
||||
int numArgs = 0;
|
||||
@ -1140,7 +1140,7 @@ static void list(Compiler* compiler, int allowAssignment)
|
||||
|
||||
// Create the list.
|
||||
emit(compiler, CODE_LIST);
|
||||
// TODO(bob): Handle lists >255 elements.
|
||||
// TODO: Handle lists >255 elements.
|
||||
emit(compiler, numElements);
|
||||
}
|
||||
|
||||
@ -1279,7 +1279,7 @@ static void number(Compiler* compiler, int allowAssignment)
|
||||
char* end;
|
||||
|
||||
double value = strtod(token->start, &end);
|
||||
// TODO(bob): Check errno == ERANGE here.
|
||||
// TODO: Check errno == ERANGE here.
|
||||
if (end == token->start)
|
||||
{
|
||||
error(compiler, "Invalid number literal.");
|
||||
@ -1307,14 +1307,14 @@ static void string(Compiler* compiler, int allowAssignment)
|
||||
|
||||
static void super_(Compiler* compiler, int allowAssignment)
|
||||
{
|
||||
// TODO(bob): Error if this is not in a method.
|
||||
// TODO: Error if this is not in a method.
|
||||
// The receiver is always stored in the first local slot.
|
||||
// TODO(bob): Will need to do something different to handle functions
|
||||
// enclosed in methods.
|
||||
// TODO: Will need to do something different to handle functions enclosed
|
||||
// in methods.
|
||||
emit(compiler, CODE_LOAD_LOCAL);
|
||||
emit(compiler, 0);
|
||||
|
||||
// TODO(bob): Super operator and constructor calls.
|
||||
// TODO: Super operator and constructor calls.
|
||||
consume(compiler, TOKEN_DOT, "Expect '.' after 'super'.");
|
||||
|
||||
// Compile the superclass call.
|
||||
@ -1344,8 +1344,8 @@ static void this_(Compiler* compiler, int allowAssignment)
|
||||
}
|
||||
|
||||
// The receiver is always stored in the first local slot.
|
||||
// TODO(bob): Will need to do something different to handle functions
|
||||
// enclosed in methods.
|
||||
// TODO: Will need to do something different to handle functions enclosed in
|
||||
// methods.
|
||||
emit(compiler, CODE_LOAD_LOCAL);
|
||||
emit(compiler, 0);
|
||||
}
|
||||
@ -1387,7 +1387,7 @@ static void subscript(Compiler* compiler, int allowAssignment)
|
||||
name[length++] = ']';
|
||||
int symbol = ensureSymbol(&compiler->parser->vm->methods, name, length);
|
||||
|
||||
// TODO(bob): Check for "=" here and handle subscript setters.
|
||||
// TODO: Check for "=" here and handle subscript setters.
|
||||
|
||||
// Compile the method call.
|
||||
emit(compiler, CODE_CALL_0 + numArgs);
|
||||
@ -1590,7 +1590,7 @@ void method(Compiler* compiler, Code instruction, int isConstructor,
|
||||
if (isConstructor) emit(&methodCompiler, CODE_NEW);
|
||||
|
||||
finishBlock(&methodCompiler);
|
||||
// TODO(bob): Single-expression methods that implicitly return the result.
|
||||
// TODO: Single-expression methods that implicitly return the result.
|
||||
|
||||
// If it's a constructor, return "this".
|
||||
if (isConstructor)
|
||||
@ -1629,7 +1629,7 @@ void block(Compiler* compiler)
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(bob): Only allowing expressions here means you can't do:
|
||||
// TODO: Only allowing expressions here means you can't do:
|
||||
//
|
||||
// if (foo) return "blah"
|
||||
//
|
||||
@ -1709,7 +1709,7 @@ void statement(Compiler* compiler)
|
||||
if (match(compiler, TOKEN_STATIC))
|
||||
{
|
||||
instruction = CODE_METHOD_STATIC;
|
||||
// TODO(bob): Need to handle fields inside static methods correctly.
|
||||
// TODO: Need to handle fields inside static methods correctly.
|
||||
// Currently, they're compiled as instance fields, which will be wrong
|
||||
// wrong wrong given that the receiver is actually the class obj.
|
||||
}
|
||||
@ -1783,7 +1783,7 @@ void statement(Compiler* compiler)
|
||||
if (match(compiler, TOKEN_RETURN))
|
||||
{
|
||||
// Compile the return value.
|
||||
// TODO(bob): Implicitly return null if there is a newline or } after the
|
||||
// TODO: Implicitly return null if there is a newline or } after the
|
||||
// "return".
|
||||
expression(compiler);
|
||||
|
||||
@ -1793,10 +1793,10 @@ void statement(Compiler* compiler)
|
||||
|
||||
if (match(compiler, TOKEN_VAR))
|
||||
{
|
||||
// TODO(bob): Variable should not be in scope until after initializer.
|
||||
// TODO: Variable should not be in scope until after initializer.
|
||||
int symbol = declareVariable(compiler);
|
||||
|
||||
// TODO(bob): Allow uninitialized vars?
|
||||
// TODO: Allow uninitialized vars?
|
||||
consume(compiler, TOKEN_EQ, "Expect '=' after variable name.");
|
||||
|
||||
// Compile the initializer.
|
||||
@ -1892,7 +1892,7 @@ ObjFn* wrenCompile(WrenVM* vm, const char* source)
|
||||
|
||||
void wrenBindMethod(ObjClass* classObj, ObjFn* fn)
|
||||
{
|
||||
// TODO(bob): What about functions nested inside [fn]?
|
||||
// TODO: What about functions nested inside [fn]?
|
||||
int ip = 0;
|
||||
for (;;)
|
||||
{
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
#define DEF_FIBER_NATIVE(native) \
|
||||
static void native_##native(WrenVM* vm, Fiber* fiber, Value* args)
|
||||
|
||||
// TODO(bob): Tune these.
|
||||
// TODO: Tune these.
|
||||
// The initial (and minimum) capacity of a non-empty list object.
|
||||
#define LIST_MIN_CAPACITY (16)
|
||||
|
||||
@ -54,7 +54,7 @@ DEF_NATIVE(bool_not)
|
||||
|
||||
DEF_NATIVE(bool_toString)
|
||||
{
|
||||
// TODO(bob): Intern these strings or something.
|
||||
// TODO: Intern these strings or something.
|
||||
if (AS_BOOL(args[0]))
|
||||
{
|
||||
return wrenNewString(vm, "true", 4);
|
||||
@ -99,7 +99,7 @@ static void ensureListCapacity(WrenVM* vm, ObjList* list, int count)
|
||||
list->capacity *= 2;
|
||||
list->elements = wrenReallocate(vm, list->elements,
|
||||
list->capacity * sizeof(Value), capacity * sizeof(Value));
|
||||
// TODO(bob): Handle allocation failure.
|
||||
// TODO: Handle allocation failure.
|
||||
list->capacity = capacity;
|
||||
}
|
||||
|
||||
@ -155,8 +155,8 @@ DEF_NATIVE(list_insert)
|
||||
|
||||
// count + 1 here so you can "insert" at the very end.
|
||||
int index = validateIndex(args[2], list->count + 1);
|
||||
// TODO(bob): Instead of returning null here, should signal an error
|
||||
// explicitly somehow.
|
||||
// TODO: Instead of returning null here, should signal an error explicitly
|
||||
// somehow.
|
||||
if (index == -1) return NULL_VAL;
|
||||
|
||||
ensureListCapacity(vm, list, list->count + 1);
|
||||
@ -176,8 +176,8 @@ DEF_NATIVE(list_removeAt)
|
||||
{
|
||||
ObjList* list = AS_LIST(args[0]);
|
||||
int index = validateIndex(args[1], list->count);
|
||||
// TODO(bob): Instead of returning null here, should signal an error
|
||||
// explicitly somehow.
|
||||
// TODO: Instead of returning null here, should signal an error explicitly
|
||||
// somehow.
|
||||
if (index == -1) return NULL_VAL;
|
||||
|
||||
Value removed = list->elements[index];
|
||||
@ -205,8 +205,8 @@ DEF_NATIVE(list_subscript)
|
||||
ObjList* list = AS_LIST(args[0]);
|
||||
|
||||
int index = validateIndex(args[1], list->count);
|
||||
// TODO(bob): Instead of returning null here, should signal an error
|
||||
// explicitly somehow.
|
||||
// TODO: Instead of returning null here, should signal an error explicitly
|
||||
// somehow.
|
||||
if (index == -1) return NULL_VAL;
|
||||
|
||||
return list->elements[index];
|
||||
@ -214,7 +214,7 @@ DEF_NATIVE(list_subscript)
|
||||
|
||||
DEF_NATIVE(null_toString)
|
||||
{
|
||||
// TODO(bob): Intern this string or something.
|
||||
// TODO: Intern this string or something.
|
||||
return wrenNewString(vm, "null", 4);
|
||||
}
|
||||
|
||||
@ -225,7 +225,7 @@ DEF_NATIVE(num_abs)
|
||||
|
||||
DEF_NATIVE(num_toString)
|
||||
{
|
||||
// TODO(bob): What size should this be?
|
||||
// TODO: What size should this be?
|
||||
char temp[100];
|
||||
sprintf(temp, "%.14g", AS_NUM(args[0]));
|
||||
return (Value)wrenNewString(vm, temp, strlen(temp));
|
||||
@ -245,7 +245,7 @@ DEF_NATIVE(num_minus)
|
||||
DEF_NATIVE(num_plus)
|
||||
{
|
||||
if (!IS_NUM(args[1])) return vm->unsupported;
|
||||
// TODO(bob): Handle coercion to string if RHS is a string.
|
||||
// TODO: Handle coercion to string if RHS is a string.
|
||||
return NUM_VAL(AS_NUM(args[0]) + AS_NUM(args[1]));
|
||||
}
|
||||
|
||||
@ -328,7 +328,7 @@ DEF_NATIVE(object_type)
|
||||
DEF_NATIVE(string_contains)
|
||||
{
|
||||
const char* string = AS_CSTRING(args[0]);
|
||||
// TODO(bob): Check type of arg first!
|
||||
// TODO: Check type of arg first!
|
||||
const char* search = AS_CSTRING(args[1]);
|
||||
|
||||
// Corner case, the empty string contains the empty string.
|
||||
@ -351,7 +351,7 @@ DEF_NATIVE(string_toString)
|
||||
DEF_NATIVE(string_plus)
|
||||
{
|
||||
if (!IS_STRING(args[1])) return vm->unsupported;
|
||||
// TODO(bob): Handle coercion to string of RHS.
|
||||
// TODO: Handle coercion to string of RHS.
|
||||
|
||||
const char* left = AS_CSTRING(args[0]);
|
||||
const char* right = AS_CSTRING(args[1]);
|
||||
@ -386,8 +386,8 @@ DEF_NATIVE(string_bangeq)
|
||||
|
||||
DEF_NATIVE(string_subscript)
|
||||
{
|
||||
// TODO(bob): Instead of returning null here, all of these failure cases
|
||||
// should signal an error explicitly somehow.
|
||||
// TODO: Instead of returning null here, all of these failure cases should
|
||||
// signal an error explicitly somehow.
|
||||
if (!IS_NUM(args[1])) return NULL_VAL;
|
||||
|
||||
double indexNum = AS_NUM(args[1]);
|
||||
@ -398,7 +398,7 @@ DEF_NATIVE(string_subscript)
|
||||
ObjString* string = AS_STRING(args[0]);
|
||||
|
||||
// Negative indices count from the end.
|
||||
// TODO(bob): Strings should cache their length.
|
||||
// TODO: Strings should cache their length.
|
||||
int length = (int)strlen(string->value);
|
||||
if (index < 0) index = length + index;
|
||||
|
||||
@ -406,7 +406,7 @@ DEF_NATIVE(string_subscript)
|
||||
if (index < 0 || index >= length) return NULL_VAL;
|
||||
|
||||
// The result is a one-character string.
|
||||
// TODO(bob): Handle UTF-8.
|
||||
// TODO: Handle UTF-8.
|
||||
Value value = wrenNewString(vm, NULL, 2);
|
||||
ObjString* result = AS_STRING(value);
|
||||
result->value[0] = AS_CSTRING(args[0])[index];
|
||||
@ -494,8 +494,8 @@ void wrenInitializeCore(WrenVM* vm)
|
||||
NATIVE(vm->numClass, ">= ", num_gte);
|
||||
NATIVE(vm->numClass, "~", num_bitwiseNot);
|
||||
|
||||
// TODO(bob): The only reason there are here is so that 0 != -0. Is that what
|
||||
// we want?
|
||||
// TODO: The only reason there are here is so that 0 != -0. Is that what we
|
||||
// want?
|
||||
NATIVE(vm->numClass, "== ", num_eqeq);
|
||||
NATIVE(vm->numClass, "!= ", num_bangeq);
|
||||
|
||||
@ -511,15 +511,15 @@ void wrenInitializeCore(WrenVM* vm)
|
||||
ObjClass* ioClass = defineClass(vm, "IO", vm->objectClass);
|
||||
NATIVE(ioClass, "write ", io_write);
|
||||
|
||||
// TODO(bob): Making this an instance is lame. The only reason we're doing it
|
||||
// is because "IO.write()" looks ugly. Maybe just get used to that?
|
||||
// TODO: Making this an instance is lame. The only reason we're doing it is
|
||||
// because "IO.write()" looks ugly. Maybe just get used to that?
|
||||
Value ioObject = wrenNewInstance(vm, ioClass);
|
||||
vm->globals[addSymbol(&vm->globalSymbols, "io", 2)] = ioObject;
|
||||
|
||||
ObjClass* osClass = defineClass(vm, "OS", vm->objectClass);
|
||||
NATIVE(osClass->metaclass, "clock", os_clock);
|
||||
|
||||
// TODO(bob): Make this a distinct object type.
|
||||
// TODO: Make this a distinct object type.
|
||||
ObjClass* unsupportedClass = wrenNewClass(vm, vm->objectClass, 0);
|
||||
vm->unsupported = (Value)wrenNewInstance(vm, unsupportedClass);
|
||||
}
|
||||
|
||||
@ -52,8 +52,8 @@ static ObjClass* newClass(WrenVM* vm, ObjClass* metaclass,
|
||||
ObjClass* wrenNewClass(WrenVM* vm, ObjClass* superclass, int numFields)
|
||||
{
|
||||
// Make the metaclass.
|
||||
// TODO(bob): What is the metaclass's metaclass?
|
||||
// TODO(bob): Handle static fields.
|
||||
// TODO: What is the metaclass's metaclass?
|
||||
// TODO: Handle static fields.
|
||||
ObjClass* metaclass = newClass(vm, NULL, vm->classClass, 0);
|
||||
|
||||
// Make sure it isn't collected when we allocate the metaclass.
|
||||
@ -89,7 +89,7 @@ ObjFn* wrenNewFunction(WrenVM* vm)
|
||||
{
|
||||
// Allocate these before the function in case they trigger a GC which would
|
||||
// free the function.
|
||||
// TODO(bob): Hack! make variable sized.
|
||||
// TODO: Hack! make variable sized.
|
||||
unsigned char* bytecode = allocate(vm, sizeof(Code) * 1024);
|
||||
Value* constants = allocate(vm, sizeof(Value) * 256);
|
||||
|
||||
|
||||
@ -32,8 +32,8 @@
|
||||
// The representation is controlled by the `NAN_TAGGING` define. If that's
|
||||
// defined, Nan tagging is used.
|
||||
|
||||
// TODO(bob): This should be in VM. (Or, really, we shouldn't hardcode this at
|
||||
// all and have growable symbol tables.)
|
||||
// TODO: This should be in VM. (Or, really, we shouldn't hardcode this at all
|
||||
// and have growable symbol tables.)
|
||||
#define MAX_SYMBOLS 256
|
||||
|
||||
typedef enum
|
||||
@ -105,7 +105,7 @@ typedef struct
|
||||
int numUpvalues;
|
||||
unsigned char* bytecode;
|
||||
|
||||
// TODO(bob): Flexible array?
|
||||
// TODO: Flexible array?
|
||||
Value* constants;
|
||||
} ObjFn;
|
||||
|
||||
@ -149,7 +149,7 @@ typedef struct
|
||||
// The function that this closure is an instance of.
|
||||
ObjFn* fn;
|
||||
|
||||
// TODO(bob): Make a flexible array.
|
||||
// TODO: Make a flexible array.
|
||||
// The upvalues this function has closed over.
|
||||
Upvalue** upvalues;
|
||||
} ObjClosure;
|
||||
@ -195,7 +195,7 @@ typedef struct sObjClass
|
||||
// of its superclass fields.
|
||||
int numFields;
|
||||
|
||||
// TODO(bob): Hack. Probably don't want to use this much space.
|
||||
// TODO: Hack. Probably don't want to use this much space.
|
||||
Method methods[MAX_SYMBOLS];
|
||||
} ObjClass;
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ WrenVM* wrenNewVM(WrenReallocateFn reallocateFn)
|
||||
|
||||
vm->bytesAllocated = 0;
|
||||
|
||||
// TODO(bob): Make this configurable.
|
||||
// TODO: Make this configurable.
|
||||
vm->nextGC = 1024 * 1024 * 10;
|
||||
vm->first = NULL;
|
||||
|
||||
@ -54,7 +54,7 @@ int wrenInterpret(WrenVM* vm, const char* source)
|
||||
ObjFn* fn = wrenCompile(vm, source);
|
||||
if (fn == NULL) return 1;
|
||||
|
||||
// TODO(bob): Return error code on runtime errors.
|
||||
// TODO: Return error code on runtime errors.
|
||||
interpret(vm, OBJ_VAL(fn));
|
||||
return 0;
|
||||
}
|
||||
@ -232,7 +232,7 @@ static void markString(WrenVM* vm, ObjString* string)
|
||||
|
||||
// Keep track of how much memory is still in use.
|
||||
vm->bytesAllocated += sizeof(ObjString);
|
||||
// TODO(bob): O(n) calculation here is lame!
|
||||
// TODO: O(n) calculation here is lame!
|
||||
vm->bytesAllocated += strlen(string->value);
|
||||
}
|
||||
|
||||
@ -410,7 +410,7 @@ void truncateSymbolTable(SymbolTable* symbols, int count)
|
||||
|
||||
int addSymbolUnchecked(SymbolTable* symbols, const char* name, size_t length)
|
||||
{
|
||||
// TODO(bob): Get rid of explicit malloc here.
|
||||
// TODO: Get rid of explicit malloc here.
|
||||
symbols->names[symbols->count] = malloc(length + 1);
|
||||
strncpy(symbols->names[symbols->count], name, length);
|
||||
symbols->names[symbols->count][length] = '\0';
|
||||
@ -439,7 +439,7 @@ int ensureSymbol(SymbolTable* symbols, const char* name, size_t length)
|
||||
int findSymbol(SymbolTable* symbols, const char* name, size_t length)
|
||||
{
|
||||
// See if the symbol is already defined.
|
||||
// TODO(bob): O(n). Do something better.
|
||||
// TODO: O(n). Do something better.
|
||||
for (int i = 0; i < symbols->count; i++)
|
||||
{
|
||||
if (strlen(symbols->names[i]) == length &&
|
||||
@ -457,7 +457,7 @@ const char* getSymbolName(SymbolTable* symbols, int symbol)
|
||||
Value findGlobal(WrenVM* vm, const char* name)
|
||||
{
|
||||
int symbol = findSymbol(&vm->globalSymbols, name, strlen(name));
|
||||
// TODO(bob): Handle failure.
|
||||
// TODO: Handle failure.
|
||||
return vm->globals[symbol];
|
||||
}
|
||||
|
||||
@ -529,7 +529,7 @@ Value interpret(WrenVM* vm, Value function)
|
||||
wrenCallFunction(fiber, function, 0);
|
||||
|
||||
// These macros are designed to only be invoked within this function.
|
||||
// TODO(bob): Check for stack overflow.
|
||||
// TODO: Check for stack overflow.
|
||||
#define PUSH(value) (fiber->stack[fiber->stackSize++] = value)
|
||||
#define POP() (fiber->stack[--fiber->stackSize])
|
||||
#define PEEK() (fiber->stack[fiber->stackSize - 1])
|
||||
@ -718,7 +718,7 @@ Value interpret(WrenVM* vm, Value function)
|
||||
wrenPrintValue(receiver);
|
||||
printf(" does not implement method \"%s\".\n",
|
||||
vm->methods.names[symbol]);
|
||||
// TODO(bob): Throw an exception or halt the fiber or something.
|
||||
// TODO: Throw an exception or halt the fiber or something.
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
@ -743,7 +743,7 @@ Value interpret(WrenVM* vm, Value function)
|
||||
CASE_CODE(SUPER_15):
|
||||
CASE_CODE(SUPER_16):
|
||||
{
|
||||
// TODO(bob): Almost completely copied from CALL. Unify somehow.
|
||||
// TODO: Almost completely copied from CALL. Unify somehow.
|
||||
|
||||
// Add one for the implicit receiver argument.
|
||||
int numArgs = instruction - CODE_SUPER_0 + 1;
|
||||
@ -791,7 +791,7 @@ Value interpret(WrenVM* vm, Value function)
|
||||
wrenPrintValue(receiver);
|
||||
printf(" does not implement method \"%s\".\n",
|
||||
vm->methods.names[symbol]);
|
||||
// TODO(bob): Throw an exception or halt the fiber or something.
|
||||
// TODO: Throw an exception or halt the fiber or something.
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
@ -849,7 +849,7 @@ Value interpret(WrenVM* vm, Value function)
|
||||
CASE_CODE(LOAD_FIELD):
|
||||
{
|
||||
int field = READ_ARG();
|
||||
// TODO(bob): We'll have to do something better here to handle functions
|
||||
// TODO: We'll have to do something better here to handle functions
|
||||
// inside methods.
|
||||
Value receiver = fiber->stack[frame->stackStart];
|
||||
ASSERT(IS_INSTANCE(receiver), "Receiver should be instance.");
|
||||
@ -862,7 +862,7 @@ Value interpret(WrenVM* vm, Value function)
|
||||
CASE_CODE(STORE_FIELD):
|
||||
{
|
||||
int field = READ_ARG();
|
||||
// TODO(bob): We'll have to do something better here to handle functions
|
||||
// TODO: We'll have to do something better here to handle functions
|
||||
// inside methods.
|
||||
Value receiver = fiber->stack[frame->stackStart];
|
||||
ASSERT(IS_INSTANCE(receiver), "Receiver should be instance.");
|
||||
@ -940,7 +940,7 @@ Value interpret(WrenVM* vm, Value function)
|
||||
|
||||
CASE_CODE(IS):
|
||||
{
|
||||
// TODO(bob): What if classObj is not a class?
|
||||
// TODO: What if classObj is not a class?
|
||||
ObjClass* expected = AS_CLASS(POP());
|
||||
Value obj = POP();
|
||||
|
||||
@ -1062,7 +1062,7 @@ Value interpret(WrenVM* vm, Value function)
|
||||
ObjClass* superclass;
|
||||
if (isSubclass)
|
||||
{
|
||||
// TODO(bob): Handle the superclass not being a class object!
|
||||
// TODO: Handle the superclass not being a class object!
|
||||
superclass = AS_CLASS(POP());
|
||||
}
|
||||
else
|
||||
@ -1114,7 +1114,7 @@ Value interpret(WrenVM* vm, Value function)
|
||||
|
||||
void wrenCallFunction(Fiber* fiber, Value function, int numArgs)
|
||||
{
|
||||
// TODO(bob): Check for stack overflow.
|
||||
// TODO: Check for stack overflow.
|
||||
fiber->frames[fiber->numFrames].fn = function;
|
||||
fiber->frames[fiber->numFrames].ip = 0;
|
||||
fiber->frames[fiber->numFrames].stackStart = fiber->stackSize - numArgs;
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
#include "wren_common.h"
|
||||
#include "wren_value.h"
|
||||
|
||||
// TODO(bob): Make these externally controllable.
|
||||
// TODO: Make these externally controllable.
|
||||
#define STACK_SIZE 1024
|
||||
#define MAX_CALL_FRAMES 256
|
||||
|
||||
@ -162,7 +162,7 @@ typedef enum
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// TODO(bob): Make this dynamically sized.
|
||||
// TODO: Make this dynamically sized.
|
||||
char* names[MAX_SYMBOLS];
|
||||
int count;
|
||||
} SymbolTable;
|
||||
@ -175,7 +175,7 @@ typedef struct
|
||||
// WrenVM has a pointer to the head of the list and walks it if a collection
|
||||
// occurs. This implies that pinned objects need to have stack semantics: only
|
||||
// the most recently pinned object can be unpinned.
|
||||
// TODO(bob): Move into wren_vm.c.
|
||||
// TODO: Move into wren_vm.c.
|
||||
typedef struct sPinnedObj
|
||||
{
|
||||
// The pinned object.
|
||||
@ -185,7 +185,7 @@ typedef struct sPinnedObj
|
||||
struct sPinnedObj* previous;
|
||||
} PinnedObj;
|
||||
|
||||
// TODO(bob): Move into wren_vm.c?
|
||||
// TODO: Move into wren_vm.c?
|
||||
struct WrenVM
|
||||
{
|
||||
SymbolTable methods;
|
||||
@ -204,15 +204,15 @@ struct WrenVM
|
||||
|
||||
SymbolTable globalSymbols;
|
||||
|
||||
// TODO(bob): Using a fixed array is gross here.
|
||||
// TODO: Using a fixed array is gross here.
|
||||
Value globals[MAX_SYMBOLS];
|
||||
|
||||
// TODO(bob): Support more than one fiber.
|
||||
// TODO: Support more than one fiber.
|
||||
Fiber* fiber;
|
||||
|
||||
// Memory management data:
|
||||
|
||||
// TODO(bob): Temp.
|
||||
// TODO: Temp.
|
||||
// The number of bytes that are known to be currently allocated. Includes all
|
||||
// memory that was proven live after the last GC, as well as any new bytes
|
||||
// that were allocated since then. Does *not* include bytes for objects that
|
||||
@ -233,7 +233,7 @@ struct WrenVM
|
||||
WrenReallocateFn reallocate;
|
||||
};
|
||||
|
||||
// TODO(bob): Move into wren_vm.c.
|
||||
// TODO: Move into wren_vm.c.
|
||||
typedef struct
|
||||
{
|
||||
// Index of the current (really next-to-be-executed) instruction in the
|
||||
@ -249,7 +249,7 @@ typedef struct
|
||||
int stackStart;
|
||||
} CallFrame;
|
||||
|
||||
// TODO(bob): Move into wren_vm.c.
|
||||
// TODO: Move into wren_vm.c.
|
||||
struct sFiber
|
||||
{
|
||||
Value stack[STACK_SIZE];
|
||||
@ -266,7 +266,7 @@ struct sFiber
|
||||
|
||||
void* wrenReallocate(WrenVM* vm, void* memory, size_t oldSize, size_t newSize);
|
||||
|
||||
// TODO(bob): Make these static or prefix their names.
|
||||
// TODO: Make these static or prefix their names.
|
||||
|
||||
// Initializes the symbol table.
|
||||
void initSymbolTable(SymbolTable* symbols);
|
||||
|
||||
@ -14,6 +14,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(bob): Closing over this.
|
||||
// TODO(bob): Close over fn/method parameter.
|
||||
// TODO(bob): Maximum number of closed-over variables (directly and/or indirect).
|
||||
// TODO: Closing over this.
|
||||
// TODO: Close over fn/method parameter.
|
||||
// TODO: Maximum number of closed-over variables (directly and/or indirect).
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
var global = "global"
|
||||
// TODO(bob): Forward reference to global declared after use.
|
||||
// TODO: Forward reference to global declared after use.
|
||||
|
||||
fn {
|
||||
io.write(global) // expect: global
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
var global = "global"
|
||||
// TODO(bob): Forward reference to global declared after use.
|
||||
// TODO: Forward reference to global declared after use.
|
||||
|
||||
class Foo {
|
||||
method {
|
||||
|
||||
@ -6,6 +6,6 @@
|
||||
// Other stuff: ឃᢆ᯽₪ℜ↩⊗┺░
|
||||
// Emoji: ☃☺♣
|
||||
|
||||
// TODO(bob): What about combining characters?
|
||||
// TODO: What about combining characters?
|
||||
|
||||
io.write("ok") // expect: ok
|
||||
|
||||
@ -7,5 +7,5 @@ var foo = Foo.new
|
||||
io.write(foo is Foo) // expect: true
|
||||
io.write(foo.toString) // expect: Foo
|
||||
|
||||
// TODO(bob): Test that class doesn't get default constructor if it has an
|
||||
// explicit one.
|
||||
// TODO: Test that class doesn't get default constructor if it has an explicit
|
||||
// one.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
class Foo {
|
||||
// TODO(bob): Do we want to require an explicit "new" here?
|
||||
// TODO: Do we want to require an explicit "new" here?
|
||||
this new { io.write("zero") }
|
||||
this new(a) { io.write(a) }
|
||||
this new(a, b) { io.write(a + b) }
|
||||
|
||||
@ -24,7 +24,7 @@ foo.write
|
||||
// expect: 4
|
||||
// expect: 5
|
||||
|
||||
// TODO(bob): Inherited fields.
|
||||
// TODO(bob): Trying to get or set a field outside of a class.
|
||||
// TODO(bob): Fields in nested classes.
|
||||
// TODO(bob): Closing over fields.
|
||||
// TODO: Inherited fields.
|
||||
// TODO: Trying to get or set a field outside of a class.
|
||||
// TODO: Fields in nested classes.
|
||||
// TODO: Closing over fields.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Single expression body.
|
||||
(fn io.write("ok")).call // expect: ok
|
||||
|
||||
// TODO(bob): Precedence of fn body.
|
||||
// TODO: Precedence of fn body.
|
||||
|
||||
// Curly body.
|
||||
fn {
|
||||
@ -29,5 +29,3 @@ fn {
|
||||
|
||||
|
||||
}.call
|
||||
|
||||
// TODO(bob): Arguments.
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
// * has higher precedence than +.
|
||||
io.write(2 + 3 * 4) // expect: 14
|
||||
|
||||
@ -26,7 +25,7 @@ io.write(false == 1 >= 2) // expect: true
|
||||
// Unary - has lower precedence than ..
|
||||
io.write(-"abc".count) // expect: -3
|
||||
|
||||
// TODO(bob): %, associativity.
|
||||
// TODO: %, associativity.
|
||||
|
||||
// Using () for grouping.
|
||||
io.write((2 * (6 - (2 + 2)))) // expect: 4
|
||||
|
||||
@ -20,8 +20,8 @@ bar.method(1, 2) // expect: bar
|
||||
bar.method(1, 2, 3) // expect: foo
|
||||
bar.method(1, 2, 3, 4) // expect: bar
|
||||
|
||||
// TODO(bob): Overriding (or BETA-style refining?).
|
||||
// TODO(bob): Private fields.
|
||||
// TODO(bob): Super (or inner) calls.
|
||||
// TODO(bob): Grammar for what expressions can follow "is".
|
||||
// TODO(bob): Prevent extending built-in types.
|
||||
// TODO: Overriding.
|
||||
// TODO: Private fields.
|
||||
// TODO: Super (or inner) calls.
|
||||
// TODO: Grammar for what expressions can follow "is".
|
||||
// TODO: Prevent extending built-in types.
|
||||
|
||||
@ -20,6 +20,6 @@ io.write((fn 1) is Object) // expect: true
|
||||
io.write("s" is Object) // expect: true
|
||||
io.write(123 is Object) // expect: true
|
||||
|
||||
// TODO(bob): Non-class on RHS.
|
||||
// TODO(bob): Precedence and associativity.
|
||||
// TODO(bob): Metaclasses ("Num is Class").
|
||||
// TODO: Non-class on RHS.
|
||||
// TODO: Precedence and associativity.
|
||||
// TODO: Metaclasses ("Num is Class").
|
||||
|
||||
@ -2,6 +2,6 @@ io.write([].count) // expect: 0
|
||||
io.write([1].count) // expect: 1
|
||||
io.write([1, 2, 3, 4].count) // expect: 4
|
||||
|
||||
// TODO(bob): Literal syntax, including newline handling.
|
||||
// TODO(bob): Unterminated list literal.
|
||||
// TODO(bob): Subscript operator.
|
||||
// TODO: Literal syntax, including newline handling.
|
||||
// TODO: Unterminated list literal.
|
||||
// TODO: Subscript operator.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// TODO(bob): What happens if the index isn't an integer?
|
||||
// TODO(bob): Out of bounds.
|
||||
// TODO: What happens if the index isn't an integer?
|
||||
// TODO: Out of bounds.
|
||||
|
||||
// Add to empty list.
|
||||
var a = []
|
||||
|
||||
@ -24,7 +24,7 @@ f.removeAt(-1)
|
||||
io.write(f) // expect: [1, 2]
|
||||
|
||||
// Out of bounds.
|
||||
// TODO(bob): Signal error in better way.
|
||||
// TODO: Signal error in better way.
|
||||
io.write([1, 2, 3].removeAt(3)) // expect: null
|
||||
io.write([1, 2, 3].removeAt(-4)) // expect: null
|
||||
|
||||
|
||||
@ -12,14 +12,14 @@ io.write(list[-2]) // expect: c
|
||||
io.write(list[-1]) // expect: d
|
||||
|
||||
// Handle out of bounds.
|
||||
// TODO(bob): Should halt the fiber or raise an error somehow.
|
||||
// TODO: Should halt the fiber or raise an error somehow.
|
||||
io.write(list[4]) // expect: null
|
||||
io.write(list[-5]) // expect: null
|
||||
|
||||
// Handle wrong argument type.
|
||||
// TODO(bob): Should halt the fiber or raise an error somehow.
|
||||
// TODO: Should halt the fiber or raise an error somehow.
|
||||
io.write(list[true]) // expect: null
|
||||
|
||||
// Handle non-integer index.
|
||||
// TODO(bob): Should halt the fiber or raise an error somehow.
|
||||
// TODO: Should halt the fiber or raise an error somehow.
|
||||
io.write(list[1.5]) // expect: null
|
||||
|
||||
@ -6,7 +6,7 @@ io.write(~23) // expect: 4294967272
|
||||
io.write(~4294967295) // expect: 0
|
||||
|
||||
// Past max u32 value.
|
||||
// TODO(bob): Is this right?
|
||||
// TODO: Is this right?
|
||||
io.write(~4294967296) // expect: 4294967295
|
||||
|
||||
// Negative numbers.
|
||||
|
||||
@ -14,5 +14,5 @@ io.write(1 >= 2) // expect: false
|
||||
io.write(2 >= 2) // expect: true
|
||||
io.write(2 >= 1) // expect: true
|
||||
|
||||
// TODO(bob): Wrong type for RHS.
|
||||
// TODO(bob): Comparing zero and negative zero.
|
||||
// TODO: Wrong type for RHS.
|
||||
// TODO: Comparing zero and negative zero.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
io.write(8 / 2) // expect: 4
|
||||
io.write(12.34 / -0.4) // expect: -30.85
|
||||
|
||||
// TODO(bob): Unsupported RHS types.
|
||||
// TODO(bob): Divide by zero.
|
||||
// TODO: Unsupported RHS types.
|
||||
// TODO: Divide by zero.
|
||||
|
||||
@ -6,5 +6,5 @@ io.write(-0) // expect: -0
|
||||
io.write(123.456) // expect: 123.456
|
||||
io.write(-0.001) // expect: -0.001
|
||||
|
||||
// TODO(bob): Hex? Scientific notation?
|
||||
// TODO(bob): Literals at and beyond numeric limits.
|
||||
// TODO: Hex? Scientific notation?
|
||||
// TODO: Literals at and beyond numeric limits.
|
||||
|
||||
@ -7,4 +7,4 @@ io.write(3 - 2 - 1) // expect: 0
|
||||
var a = 3
|
||||
io.write(-a) // expect: -3
|
||||
|
||||
// TODO(bob): Unsupported RHS types.
|
||||
// TODO: Unsupported RHS types.
|
||||
|
||||
@ -10,5 +10,5 @@ io.write(-4.2 % -3.1) // expect: -1.1
|
||||
// Left associative.
|
||||
io.write(13 % 7 % 4) // expect: 2
|
||||
|
||||
// TODO(bob): Unsupported RHS types.
|
||||
// TODO(bob): Error on mod by zero.
|
||||
// TODO: Unsupported RHS types.
|
||||
// TODO: Error on mod by zero.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
io.write(5 * 3) // expect: 15
|
||||
io.write(12.34 * 0.3) // expect: 3.702
|
||||
|
||||
// TODO(bob): Unsupported RHS types.
|
||||
// TODO: Unsupported RHS types.
|
||||
|
||||
@ -2,4 +2,4 @@ io.write(1 + 2) // expect: 3
|
||||
io.write(12.34 + 0.13) // expect: 12.47
|
||||
io.write(3 + 5 + 2) // expect: 10
|
||||
|
||||
// TODO(bob): Unsupported RHS types.
|
||||
// TODO: Unsupported RHS types.
|
||||
|
||||
@ -5,4 +5,4 @@ io.write("something".contains("some")) // expect: true
|
||||
io.write("something".contains("ing")) // expect: true
|
||||
io.write("something".contains("math")) // expect: false
|
||||
|
||||
// TODO(bob): Passing non-string as argument.
|
||||
// TODO: Passing non-string as argument.
|
||||
|
||||
@ -4,5 +4,5 @@ io.write("\\") // expect: \
|
||||
io.write("(\n)") // expect: (
|
||||
// expect: )
|
||||
|
||||
// TODO(bob): Non-printing escapes like \t.
|
||||
// TODO(bob): Unicode escape sequences.
|
||||
// TODO: Non-printing escapes like \t.
|
||||
// TODO: Unicode escape sequences.
|
||||
|
||||
@ -11,14 +11,14 @@ io.write("abcd"[-2]) // expect: c
|
||||
io.write("abcd"[-1]) // expect: d
|
||||
|
||||
// Handle out of bounds.
|
||||
// TODO(bob): Should halt the fiber or raise an error somehow.
|
||||
// TODO: Should halt the fiber or raise an error somehow.
|
||||
io.write("abcd"[4]) // expect: null
|
||||
io.write("abcd"[-5]) // expect: null
|
||||
|
||||
// Handle wrong argument type.
|
||||
// TODO(bob): Should halt the fiber or raise an error somehow.
|
||||
// TODO: Should halt the fiber or raise an error somehow.
|
||||
io.write("abcd"[true]) // expect: null
|
||||
|
||||
// Handle non-integer index.
|
||||
// TODO(bob): Should halt the fiber or raise an error somehow.
|
||||
// TODO: Should halt the fiber or raise an error somehow.
|
||||
io.write("abcd"[1.5]) // expect: null
|
||||
|
||||
@ -15,8 +15,8 @@ Derived.new.bar
|
||||
// expect: Derived.bar
|
||||
// expect: Base.foo
|
||||
|
||||
// TODO(bob): Super constructor calls.
|
||||
// TODO(bob): Super operator calls.
|
||||
// TODO(bob): Calling super outside of a class.
|
||||
// TODO(bob): Super calls inside nested functions in methods.
|
||||
// TODO(bob): Super where there is no inherited method.
|
||||
// TODO: Super constructor calls.
|
||||
// TODO: Super operator calls.
|
||||
// TODO: Calling super outside of a class.
|
||||
// TODO: Super calls inside nested functions in methods.
|
||||
// TODO: Super where there is no inherited method.
|
||||
|
||||
Reference in New Issue
Block a user