5 Commits

Author SHA1 Message Date
ff9899e2e2 tweak doc/site/modularity.markdown
Co-authored-by: Thorbjørn Lindeijer <bjorn@lindeijer.nl>
2020-07-11 13:20:47 -07:00
00bf53e3cb tweak doc/site/modularity.markdown
Co-authored-by: Thorbjørn Lindeijer <bjorn@lindeijer.nl>
2020-07-11 13:20:38 -07:00
c726f7a26c docs; update reserved words list 2020-07-10 20:35:29 -07:00
786e4c8ed4 docs; update for import as 2020-07-10 20:31:53 -07:00
03b44ca6f1 Add import "..." for Variable as OtherName
replaces #464 - https://github.com/wren-lang/wren/pull/464
2020-07-10 20:20:03 -07:00
7 changed files with 68 additions and 22 deletions

View File

@ -42,6 +42,17 @@ if (thirsty) {
} }
</pre> </pre>
If you need to import a variable under a different name, you can use
`import "..." for Name as OtherName`. This looks up the top-level variable
`Name` in *that* module, but declares a variable called `OtherName` in *this* module
with its value.
<pre class="snippet">
import "liquids" for Water //Water is now taken
import "beverages" for Coffee, Water as H2O, Tea
// var water = H2O.new()
</pre>
If you want to load a module, but not bind any variables from it, you can omit If you want to load a module, but not bind any variables from it, you can omit
the `for` clause: the `for` clause:

File diff suppressed because one or more lines are too long

View File

@ -43,7 +43,7 @@ One way to get a quick feel for a language's style is to see what words it
reserves. Here's what Wren has: reserves. Here's what Wren has:
<pre class="snippet"> <pre class="snippet">
break class construct else false for foreign if import as break class construct else false for foreign if import
in is null return static super this true var while in is null return static super this true var while
</pre> </pre>

View File

@ -95,6 +95,7 @@ typedef enum
TOKEN_FOREIGN, TOKEN_FOREIGN,
TOKEN_IF, TOKEN_IF,
TOKEN_IMPORT, TOKEN_IMPORT,
TOKEN_AS,
TOKEN_IN, TOKEN_IN,
TOKEN_IS, TOKEN_IS,
TOKEN_NULL, TOKEN_NULL,
@ -575,6 +576,7 @@ static Keyword keywords[] =
{"foreign", 7, TOKEN_FOREIGN}, {"foreign", 7, TOKEN_FOREIGN},
{"if", 2, TOKEN_IF}, {"if", 2, TOKEN_IF},
{"import", 6, TOKEN_IMPORT}, {"import", 6, TOKEN_IMPORT},
{"as", 2, TOKEN_AS},
{"in", 2, TOKEN_IN}, {"in", 2, TOKEN_IN},
{"is", 2, TOKEN_IS}, {"is", 2, TOKEN_IS},
{"null", 4, TOKEN_NULL}, {"null", 4, TOKEN_NULL},
@ -2629,6 +2631,7 @@ GrammarRule rules[] =
/* TOKEN_FOREIGN */ UNUSED, /* TOKEN_FOREIGN */ UNUSED,
/* TOKEN_IF */ UNUSED, /* TOKEN_IF */ UNUSED,
/* TOKEN_IMPORT */ UNUSED, /* TOKEN_IMPORT */ UNUSED,
/* TOKEN_AS */ UNUSED,
/* TOKEN_IN */ UNUSED, /* TOKEN_IN */ UNUSED,
/* TOKEN_IS */ INFIX_OPERATOR(PREC_IS, "is"), /* TOKEN_IS */ INFIX_OPERATOR(PREC_IS, "is"),
/* TOKEN_NULL */ PREFIX(null), /* TOKEN_NULL */ PREFIX(null),
@ -2721,7 +2724,6 @@ static int getByteCountForArguments(const uint8_t* bytecode,
case CODE_FOREIGN_CONSTRUCT: case CODE_FOREIGN_CONSTRUCT:
case CODE_FOREIGN_CLASS: case CODE_FOREIGN_CLASS:
case CODE_END_MODULE: case CODE_END_MODULE:
case CODE_IMPORT_MODULE:
return 0; return 0;
case CODE_LOAD_LOCAL: case CODE_LOAD_LOCAL:
@ -2762,6 +2764,7 @@ static int getByteCountForArguments(const uint8_t* bytecode,
case CODE_OR: case CODE_OR:
case CODE_METHOD_INSTANCE: case CODE_METHOD_INSTANCE:
case CODE_METHOD_STATIC: case CODE_METHOD_STATIC:
case CODE_IMPORT_MODULE:
case CODE_IMPORT_VARIABLE: case CODE_IMPORT_VARIABLE:
return 2; return 2;
@ -3343,18 +3346,11 @@ static void classDefinition(Compiler* compiler, bool isForeign)
static void import(Compiler* compiler) static void import(Compiler* compiler)
{ {
ignoreNewlines(compiler); ignoreNewlines(compiler);
consume(compiler, TOKEN_STRING, "Expect a string after 'import'.");
if(match(compiler, TOKEN_STRING)) { int moduleConstant = addConstant(compiler, compiler->parser->previous.value);
int constant = addConstant(compiler, compiler->parser->previous.value);
emitShortArg(compiler, CODE_CONSTANT, constant);
} else if(match(compiler, TOKEN_INTERPOLATION)) {
stringInterpolation(compiler, false);
} else {
error(compiler, "Expect a string after 'import'");
}
// Load the module. // Load the module.
emitOp(compiler, CODE_IMPORT_MODULE); emitShortArg(compiler, CODE_IMPORT_MODULE, moduleConstant);
// Discard the unused result value from calling the module body's closure. // Discard the unused result value from calling the module body's closure.
emitOp(compiler, CODE_POP); emitOp(compiler, CODE_POP);
@ -3366,16 +3362,37 @@ static void import(Compiler* compiler)
do do
{ {
ignoreNewlines(compiler); ignoreNewlines(compiler);
int slot = declareNamedVariable(compiler);
// Define a string constant for the variable name. consume(compiler, TOKEN_NAME, "Expect variable name.");
int variableConstant = addConstant(compiler,
wrenNewStringLength(compiler->parser->vm, // We need to hold onto the source variable,
compiler->parser->previous.start, // in order to reference it in the import later
compiler->parser->previous.length)); Token sourceVariableToken = compiler->parser->previous;
// Define a string constant for the original variable name.
int sourceVariableConstant = addConstant(compiler,
wrenNewStringLength(compiler->parser->vm,
sourceVariableToken.start,
sourceVariableToken.length));
// Store the symbol we care about for the variable
int slot = -1;
if(match(compiler, TOKEN_AS))
{
//import "module" for Source as Dest
//Use 'Dest' as the name by declaring a new variable for it.
//This parses a name after the 'as' and defines it.
slot = declareNamedVariable(compiler);
}
else
{
//import "module" for Source
//Uses 'Source' as the name directly
slot = declareVariable(compiler, &sourceVariableToken);
}
// Load the variable from the other module. // Load the variable from the other module.
emitShortArg(compiler, CODE_IMPORT_VARIABLE, variableConstant); emitShortArg(compiler, CODE_IMPORT_VARIABLE, sourceVariableConstant);
// Store the result in the variable here. // Store the result in the variable here.
defineVariable(compiler, slot); defineVariable(compiler, slot);

View File

@ -1281,7 +1281,7 @@ static WrenInterpretResult runInterpreter(WrenVM* vm, register ObjFiber* fiber)
// value. It will be popped after this fiber is resumed. Store the // value. It will be popped after this fiber is resumed. Store the
// imported module's closure in the slot in case a GC happens when // imported module's closure in the slot in case a GC happens when
// invoking the closure. // invoking the closure.
PUSH(importModule(vm, POP())); PUSH(importModule(vm, fn->constants.data[READ_SHORT()]));
if (wrenHasError(fiber)) RUNTIME_ERROR(); if (wrenHasError(fiber)) RUNTIME_ERROR();
// If we get a closure, call it to execute the module body. // If we get a closure, call it to execute the module body.

View File

@ -0,0 +1,11 @@
var Module = "from here"
var ValueC = "value C"
import "./module" for ValueA, Module as Another, ValueB // expect: ran module
import "./module" for ValueC as OtherC
System.print(Module) // expect: from here
System.print(Another) // expect: from module
System.print(ValueA) // expect: module A
System.print(ValueB) // expect: module B
System.print(ValueC) // expect: value C
System.print(OtherC) // expect: module C

View File

@ -0,0 +1,7 @@
// nontest
var Module = "from module"
System.print("ran module")
var ValueA = "module A"
var ValueB = "module B"
var ValueC = "module C"