mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-12 06:38:45 +01:00
Map literals!
This commit is contained in:
@ -1315,7 +1315,8 @@ typedef enum
|
||||
PREC_TERM, // + -
|
||||
PREC_FACTOR, // * / %
|
||||
PREC_UNARY, // unary - ! ~
|
||||
PREC_CALL // . () []
|
||||
PREC_CALL, // . () []
|
||||
PREC_PRIMARY
|
||||
} Precedence;
|
||||
|
||||
typedef void (*GrammarFn)(Compiler*, bool allowAssignment);
|
||||
@ -1574,12 +1575,14 @@ static void loadThis(Compiler* compiler)
|
||||
}
|
||||
}
|
||||
|
||||
// A parenthesized expression.
|
||||
static void grouping(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
expression(compiler);
|
||||
consume(compiler, TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
|
||||
}
|
||||
|
||||
// A list literal.
|
||||
static void list(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
// Compile the list elements.
|
||||
@ -1603,6 +1606,54 @@ static void list(Compiler* compiler, bool allowAssignment)
|
||||
emitByteArg(compiler, CODE_LIST, numElements);
|
||||
}
|
||||
|
||||
// A map literal.
|
||||
static void map(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
// TODO: Do we want to do the same thing for list literals and remove the
|
||||
// bytecodes for them?
|
||||
|
||||
// Load the Map class.
|
||||
int mapClassSymbol = wrenSymbolTableFind(&compiler->parser->vm->globalNames,
|
||||
"Map", 3);
|
||||
ASSERT(mapClassSymbol != -1, "Should have already defined 'Map' global.");
|
||||
emitShortArg(compiler, CODE_LOAD_GLOBAL, mapClassSymbol);
|
||||
|
||||
// Instantiate a new map.
|
||||
emitShortArg(compiler, CODE_CALL_0,
|
||||
methodSymbol(compiler, " instantiate", 12));
|
||||
|
||||
int subscriptSetSymbol = methodSymbol(compiler, "[ ]=", 4);
|
||||
|
||||
// Compile the map elements. Each one is compiled to just invoke the
|
||||
// subscript setter on the map.
|
||||
if (peek(compiler) != TOKEN_RIGHT_BRACE)
|
||||
{
|
||||
do
|
||||
{
|
||||
ignoreNewlines(compiler);
|
||||
|
||||
// Push a copy of the map since the subscript call will consume it.
|
||||
emit(compiler, CODE_DUP);
|
||||
|
||||
// The key.
|
||||
parsePrecedence(compiler, false, PREC_PRIMARY);
|
||||
consume(compiler, TOKEN_COLON, "Expect ':' after map key.");
|
||||
|
||||
// The value.
|
||||
expression(compiler);
|
||||
|
||||
emitShortArg(compiler, CODE_CALL_2, subscriptSetSymbol);
|
||||
|
||||
// Discard the result of the setter call.
|
||||
emit(compiler, CODE_POP);
|
||||
} while (match(compiler, TOKEN_COMMA));
|
||||
}
|
||||
|
||||
// Allow newlines before the closing '}'.
|
||||
ignoreNewlines(compiler);
|
||||
consume(compiler, TOKEN_RIGHT_BRACE, "Expect '}' after map entries.");
|
||||
}
|
||||
|
||||
// Unary operators like `-foo`.
|
||||
static void unaryOp(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
@ -2174,7 +2225,7 @@ GrammarRule rules[] =
|
||||
/* TOKEN_RIGHT_PAREN */ UNUSED,
|
||||
/* TOKEN_LEFT_BRACKET */ { list, subscript, subscriptSignature, PREC_CALL, NULL },
|
||||
/* TOKEN_RIGHT_BRACKET */ UNUSED,
|
||||
/* TOKEN_LEFT_BRACE */ UNUSED,
|
||||
/* TOKEN_LEFT_BRACE */ PREFIX(map),
|
||||
/* TOKEN_RIGHT_BRACE */ UNUSED,
|
||||
/* TOKEN_COLON */ UNUSED,
|
||||
/* TOKEN_DOT */ INFIX(PREC_CALL, call),
|
||||
@ -2297,6 +2348,7 @@ static int getNumArguments(const uint8_t* bytecode, const Value* constants,
|
||||
case CODE_FALSE:
|
||||
case CODE_TRUE:
|
||||
case CODE_POP:
|
||||
case CODE_DUP:
|
||||
case CODE_IS:
|
||||
case CODE_CLOSE_UPVALUE:
|
||||
case CODE_RETURN:
|
||||
|
||||
@ -110,6 +110,7 @@ static int debugPrintInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine)
|
||||
case CODE_STORE_FIELD: BYTE_INSTRUCTION("STORE_FIELD");
|
||||
|
||||
case CODE_POP: printf("POP\n"); break;
|
||||
case CODE_DUP: printf("DUP\n"); break;
|
||||
|
||||
case CODE_CALL_0:
|
||||
case CODE_CALL_1:
|
||||
|
||||
@ -450,6 +450,7 @@ static bool runInterpreter(WrenVM* vm)
|
||||
&&code_LOAD_FIELD,
|
||||
&&code_STORE_FIELD,
|
||||
&&code_POP,
|
||||
&&code_DUP,
|
||||
&&code_CALL_0,
|
||||
&&code_CALL_1,
|
||||
&&code_CALL_2,
|
||||
@ -559,6 +560,8 @@ static bool runInterpreter(WrenVM* vm)
|
||||
}
|
||||
|
||||
CASE_CODE(POP): DROP(); DISPATCH();
|
||||
CASE_CODE(DUP): PUSH(PEEK()); DISPATCH();
|
||||
|
||||
CASE_CODE(NULL): PUSH(NULL_VAL); DISPATCH();
|
||||
CASE_CODE(FALSE): PUSH(FALSE_VAL); DISPATCH();
|
||||
CASE_CODE(TRUE): PUSH(TRUE_VAL); DISPATCH();
|
||||
|
||||
@ -77,6 +77,9 @@ typedef enum
|
||||
// Pop and discard the top of stack.
|
||||
CODE_POP,
|
||||
|
||||
// Push a copy of the value currently on the top of the stack.
|
||||
CODE_DUP,
|
||||
|
||||
// Invoke the method with symbol [arg]. The number indicates the number of
|
||||
// arguments (not including the receiver).
|
||||
CODE_CALL_0,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
var map = new Map
|
||||
var map = {}
|
||||
IO.print(map.count) // expect: 0
|
||||
map["one"] = "value"
|
||||
IO.print(map.count) // expect: 1
|
||||
|
||||
1
test/map/eof_after_colon.wren
Normal file
1
test/map/eof_after_colon.wren
Normal file
@ -0,0 +1 @@
|
||||
var map = {1: // expect error
|
||||
2
test/map/eof_after_comma.wren
Normal file
2
test/map/eof_after_comma.wren
Normal file
@ -0,0 +1,2 @@
|
||||
var map = {1: 2,
|
||||
// expect error
|
||||
1
test/map/eof_after_key.wren
Normal file
1
test/map/eof_after_key.wren
Normal file
@ -0,0 +1 @@
|
||||
var map = {1 // expect error
|
||||
2
test/map/eof_after_value.wren
Normal file
2
test/map/eof_after_value.wren
Normal file
@ -0,0 +1,2 @@
|
||||
var map = {1: 2
|
||||
// expect error
|
||||
@ -58,7 +58,7 @@ var fishes = [
|
||||
"Cutlassfish", "Cutthroat eel", "Cutthroat trout"
|
||||
]
|
||||
|
||||
var map = new Map
|
||||
var map = {}
|
||||
for (fish in fishes) {
|
||||
map[fish] = fish.count
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
var map = new Map
|
||||
|
||||
map[null] = "null value"
|
||||
map[true] = "true value"
|
||||
map[false] = "false value"
|
||||
map[0] = "zero"
|
||||
map[1.2] = "1 point 2"
|
||||
map[List] = "list class"
|
||||
map["null"] = "string value"
|
||||
map[1..3] = "1 to 3"
|
||||
var map = {
|
||||
null: "null value",
|
||||
true: "true value",
|
||||
false: "false value",
|
||||
0: "zero",
|
||||
1.2: "1 point 2",
|
||||
List: "list class",
|
||||
"null": "string value",
|
||||
(1..3): "1 to 3"
|
||||
}
|
||||
|
||||
IO.print(map[null]) // expect: null value
|
||||
IO.print(map[true]) // expect: true value
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
// TODO: Use map literal.
|
||||
|
||||
IO.print(new Map is Map) // expect: true
|
||||
IO.print({} is Map) // expect: true
|
||||
// TODO: Abstract base class for associations.
|
||||
IO.print(new Map is Object) // expect: true
|
||||
IO.print(new Map is Bool) // expect: false
|
||||
IO.print((new Map).type == Map) // expect: true
|
||||
IO.print({} is Object) // expect: true
|
||||
IO.print({} is Bool) // expect: false
|
||||
IO.print({}.type == Map) // expect: true
|
||||
|
||||
Reference in New Issue
Block a user