Skip to content

Commit

Permalink
Merge pull request #64 from leonidborisenko/import-macro-statement
Browse files Browse the repository at this point in the history
Import macro with shorthand 'import macro ...' syntax
  • Loading branch information
richardhundt committed Sep 24, 2014
2 parents 6d993b6 + 170aeed commit f180fea
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 12 deletions.
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -946,11 +946,15 @@ around it.

#### <a name="import-statement"></a>Import Statement

`import (<alias> = )? <symbol> (, (<alias> = )? <symbol>)* from <expr>`
`import macro? (<alias> = )? <symbol> (, (<alias> = )? <symbol>)* from <expr>`

Calls `require(expr)` and then extracts and assigns the named symbols
to `local` variables. May be used anywhere.

`import macro ...` doesn't assign the named symbols to `local` variables, but
introduces them as [macros](#macros) in current scope. `import macro ..` is a
compile time statement evaluated in translating phase.

#### <a name="export-statement"></a>Export Statement

`export <ident> (, <ident>)*`
Expand Down Expand Up @@ -1633,8 +1637,9 @@ $ shinec -o hello.shn
This comes with a couple of caveats. First, the compiler needs to
load and evaluate the module at compile time, so if the module's
code has side effects (such as sending an email), then this will
happen when the code is *compiled*. This is the only case where the
compiler does any sort of early linking or binding.
happen when the code is *compiled*. This is the only case (along with
`import macro ...` statement) where the compiler does any sort of early
linking or binding.

Secondly, if the function to be used as the macro implementation is
declared in the same compilation unit, then it must be declared in
Expand All @@ -1646,6 +1651,13 @@ what they need locally.

Some tips:

* Macros could be imported with shorthand syntax:
```
-- file: hello.shn
import macro hello from "macros"
hello("World!")
```
* To implement macros, one needs to know the structure of the
AST, so `shinec -p` will print it out.
* The "shine.lang.util" module has a `dump` function which pretty
Expand Down
5 changes: 4 additions & 1 deletion src/lang/parser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,12 @@ local patt = [=[
) -> exportStmt
import_stmt <- (
"import" <idsafe> s (<import_from> / <import_path>)
"import" <idsafe> s
({<import_macro_keyword>?} (<import_from> / <import_path>)) -> importStmt
)
import_macro_keyword <- "macro" <idsafe> s
import_path <- {| <import_path_expr> |} -> importPath
import_path_expr <- (
Expand Down
55 changes: 47 additions & 8 deletions src/lang/translator.lua
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,45 @@ end

local translate

local function import_macro_func(import, package_name, func_name)
local errs = string.format(
"imported macro body for '%s' cannot be resolved",
name)
assert(type(package_name) == 'string', errs)
package_name = util.unquote(package_name)
local func = import(package_name, func_name)
assert(func ~= nil, errs)
return func
end

local function iterate_imported_symbols(import_stmt_node)
local function iterator(names_num, i)
if i >= names_num then return end
i = i + 1
local current_name = import_stmt_node.names[i]
local imported_symbol_alias = current_name[1].name
local imported_symbol
if current_name[2] then
imported_symbol = current_name[2].name
else
imported_symbol = imported_symbol_alias
end
return i, imported_symbol_alias, imported_symbol
end
return iterator, #import_stmt_node.names, 0
end

function match:ImportStatement(node)
if node.macro then
local import = require("core").__magic__.import
local package_name = self:get(node.from)
for i, macro_name, func_name in iterate_imported_symbols(node) do
local macro_func = import_macro_func(import, package_name, func_name)
self.ctx.scope.macro[macro_name] = macro_func
end
return OpChunk{ }
end

local args = OpList{ self:get(node.from) }
local syms = OpList{ }
for i=1, #node.names do
Expand Down Expand Up @@ -376,14 +414,15 @@ function match:MacroDeclaration(node)
local info = self.ctx:lookup(nref)
if info.type == 'import' then
local from = self:get(info.node.from)
local errs = string.format(
"imported macro body for '%s' cannot be resolved",
name)
assert(type(from) == 'string', errs)
from = util.unquote(from)
local pckg = require(from)
func = pckg[nref]
assert(func ~= nil, errs)
local function import(package_name, func_name)
return require(package_name)[func_name]
end
for i, alias, func_name in iterate_imported_symbols(info.node) do
if alias == nref then
func = import_macro_func(import, from, func_name)
break
end
end
elseif info.type == 'function' then
local defn = self:get(info.node)
local wrap = OpChunk{ defn, Op{'!return', nref} }
Expand Down
4 changes: 4 additions & 0 deletions src/lang/tree.lua
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ end
function defs.rawExpr(expr)
return { type = "RawExpression", expression = expr }
end
function defs.importStmt(macro_keyword, node)
node.macro = (#macro_keyword ~= 0)
return node
end
function defs.importFrom(names, from)
return { type = "ImportStatement", names = names, from = from }
end
Expand Down

0 comments on commit f180fea

Please sign in to comment.