diff --git a/doc/site/modularity.markdown b/doc/site/modularity.markdown index 8c3ade7ca..ba054fc9a 100644 --- a/doc/site/modularity.markdown +++ b/doc/site/modularity.markdown @@ -42,6 +42,17 @@ if (thirsty) { } +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. + +
+import "liquids" for Water //Water is now taken
+import "beverages" for Coffee, Water as H2O, Tea
+// var water = H2O.new()
+
+ If you want to load a module, but not bind any variables from it, you can omit the `for` clause: diff --git a/doc/site/static/prism.js b/doc/site/static/prism.js index f6770127d..9518cecad 100644 --- a/doc/site/static/prism.js +++ b/doc/site/static/prism.js @@ -3,4 +3,4 @@ https://prismjs.com/download.html#themes=prism&languages=clike+c+lua */ var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var c=/\blang(?:uage)?-([\w-]+)\b/i,n=0,C={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof _?new _(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/n.length)return;if(!(b instanceof _)){var x=1;if(d&&y!=t.tail.prev){g.lastIndex=k;var w=g.exec(n);if(!w)break;var A=w.index+(h&&w[1]?w[1].length:0),P=w.index+w[0].length,S=k;for(S+=y.value.length;S<=A;)y=y.next,S+=y.value.length;if(S-=y.value.length,k=S,y.value instanceof _)continue;for(var O=y;O!==t.tail&&(S"+a.content+""},!u.document)return u.addEventListener&&(C.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),t=n.language,r=n.code,a=n.immediateClose;u.postMessage(C.highlight(r,C.languages[t],t)),a&&u.close()},!1)),C;var e=C.util.currentScript();function t(){C.manual||C.highlightAll()}if(e&&(C.filename=e.src,e.hasAttribute("data-manual")&&(C.manual=!0)),!C.manual){var r=document.readyState;"loading"===r||"interactive"===r&&e&&e.defer?document.addEventListener("DOMContentLoaded",t):window.requestAnimationFrame?window.requestAnimationFrame(t):window.setTimeout(t,16)}return C}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|interface|extends|implements|trait|instanceof|new)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/}; Prism.languages.c=Prism.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+/,lookbehind:!0},keyword:/\b(?:__attribute__|_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,function:/[a-z_]\w*(?=\s*\()/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/,number:/(?:\b0x(?:[\da-f]+\.?[\da-f]*|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?)[ful]*/i}),Prism.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+(?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},Prism.languages.c.string],comment:Prism.languages.c.comment,directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"}}},constant:/\b(?:__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\b/}),delete Prism.languages.c.boolean; -Prism.languages.lua={comment:/^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)|\/\/(?:.+)/m,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[\s\S]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,greedy:!0},number:/\b0x[a-f\d]+\.?[a-f\d]*(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|\.?\d*(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,keyword:/\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while|class|construct|foreign|import|is|null|static|super|this|var)\b/,function:/(?!\d)\w+(?=\s*(?:[({]))/,operator:[/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\.\.(?!\.)/,lookbehind:!0}],punctuation:/[\[\](){},;]|\.+|:+/}; +Prism.languages.lua={comment:/^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)|\/\/(?:.+)/m,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[\s\S]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,greedy:!0},number:/\b0x[a-f\d]+\.?[a-f\d]*(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|\.?\d*(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,keyword:/\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while|class|construct|as|foreign|import|is|null|static|super|this|var)\b/,function:/(?!\d)\w+(?=\s*(?:[({]))/,operator:[/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\.\.(?!\.)/,lookbehind:!0}],punctuation:/[\[\](){},;]|\.+|:+/}; diff --git a/doc/site/syntax.markdown b/doc/site/syntax.markdown index 57cffa54e..ac3f315f1 100644 --- a/doc/site/syntax.markdown +++ b/doc/site/syntax.markdown @@ -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:
-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
 
diff --git a/src/vm/wren_compiler.c b/src/vm/wren_compiler.c index ee8eb78a6..e2e802410 100644 --- a/src/vm/wren_compiler.c +++ b/src/vm/wren_compiler.c @@ -95,6 +95,7 @@ typedef enum TOKEN_FOREIGN, TOKEN_IF, TOKEN_IMPORT, + TOKEN_AS, TOKEN_IN, TOKEN_IS, TOKEN_NULL, @@ -575,6 +576,7 @@ static Keyword keywords[] = {"foreign", 7, TOKEN_FOREIGN}, {"if", 2, TOKEN_IF}, {"import", 6, TOKEN_IMPORT}, + {"as", 2, TOKEN_AS}, {"in", 2, TOKEN_IN}, {"is", 2, TOKEN_IS}, {"null", 4, TOKEN_NULL}, @@ -2629,6 +2631,7 @@ GrammarRule rules[] = /* TOKEN_FOREIGN */ UNUSED, /* TOKEN_IF */ UNUSED, /* TOKEN_IMPORT */ UNUSED, + /* TOKEN_AS */ UNUSED, /* TOKEN_IN */ UNUSED, /* TOKEN_IS */ INFIX_OPERATOR(PREC_IS, "is"), /* TOKEN_NULL */ PREFIX(null), @@ -3359,17 +3362,38 @@ static void import(Compiler* compiler) do { ignoreNewlines(compiler); - int slot = declareNamedVariable(compiler); - // Define a string constant for the variable name. - int variableConstant = addConstant(compiler, - wrenNewStringLength(compiler->parser->vm, - compiler->parser->previous.start, - compiler->parser->previous.length)); + consume(compiler, TOKEN_NAME, "Expect variable name."); + // We need to hold onto the source variable, + // in order to reference it in the import later + 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. - emitShortArg(compiler, CODE_IMPORT_VARIABLE, variableConstant); - + emitShortArg(compiler, CODE_IMPORT_VARIABLE, sourceVariableConstant); + // Store the result in the variable here. defineVariable(compiler, slot); } while (match(compiler, TOKEN_COMMA)); diff --git a/test/language/module/import_as/import_as.wren b/test/language/module/import_as/import_as.wren new file mode 100644 index 000000000..9874869e8 --- /dev/null +++ b/test/language/module/import_as/import_as.wren @@ -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 diff --git a/test/language/module/import_as/module.wren b/test/language/module/import_as/module.wren new file mode 100644 index 000000000..12155b8f2 --- /dev/null +++ b/test/language/module/import_as/module.wren @@ -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" \ No newline at end of file