Skip to content

Instantly share code, notes, and snippets.

@fowlmouth
Last active August 29, 2015 14:02
Show Gist options
  • Save fowlmouth/8cc9ee26bcf509b5fea5 to your computer and use it in GitHub Desktop.
Save fowlmouth/8cc9ee26bcf509b5fea5 to your computer and use it in GitHub Desktop.
#
# This module is dedicated to Marijuana. I love you.
#
# herein lies a macro called import_repo which accepts
# somewhat of a URL, something like github.com/you/repository/module
# the repository will be cloned and imported, like that other
# language's import statement. with metaprogramming, not baked
# into the compiler, like that other language.
#
# at the moment github.com and bitbucket.com (for git) is supported
#
# the programming language which may or may not be named
# 'go' can suck it.
#
# test included at the bottom of the file
#
import macros, os, strutils
proc createDirCT (dir:string) {.compiletime.} =
# hack
when defined(Linux):
discard staticExec("mkdir -p "&dir)
else:
{.error: "no implement".}
type
TDomain = enum
wtf, # repo field is an error message
github,
bitbucket
repo_import = tuple
domain:TDomain
repo, module:string
proc parse_import (x: pnimrodnode): repo_import {.compileTime.} =
var
repo = ""
n = x
cbs = newseq[proc(str:var string)]()
while true:
#echo n.kind
## TODO account for "as" here
if n.kind == nnkInfix and n[0].ident == !"/":
#echo treerepr(n)
let right = n[2]
n = n[1]
cbs.add(proc (str:var string) =
#echo "right: ", right
if right.kind == nnkIdent:
let dir = $ right.ident
if str.len > 0: str.add '/'
str.add dir
)
elif n.kind == nnkDotExpr:
let dom = repr(n)
if dom.eqIdent("github.com"):
result.domain = github
break
elif dom.eqIdent("bitbucket.org"):
result.domain = bitbucket
break
else:
return (wtf, "domain "& dom &" is unknown, please write support","")
break
else:
return (wtf, "wtf is "& repr(n),"")
assert result[0] != wtf
## run the callbacks backwards, since they are inside out
## good test of compiletime closures :)
assert cbs.len > 1
for i in countdown(high(cbs),high(cbs)-1): cbs[i](repo)
var module = ""
for i in countdown(high(cbs)-2,0): cbs[i](module)
assert n.kind == nnkDotExpr
result.repo = repo
result.module =
if module.len == 0: repo[repo.rfind("/")+1 .. -1]
else: module
#echo "domain: ", result.repr
macro import_repo* (files: expr): stmt {.immediate.} =
let cs = callsite()
cs.expectKind nnkCommand
if cs.len == 1: return newEmptyNode()
var imports: seq[repo_import] = @[]
for i in 1.. <len(cs):
let f = cs[i]
let x = parse_import(f)
if x[0] == wtf:
echo x[1]
else:
imports.add x
if imports.len == 0:
return newEmptyNode()
proc git_clone (url,dir:string) =
when defined(Linux):
echo staticExec("""pushd $# ; pwd ; git clone --depth 1 $# . ; popd""".format(
dir, url
))
else:
{.error: "implement me".}
# git@bitbucket.org:$2.git
proc github_clone (repos,dir:string) =
git_clone "git@github.com:$#.git" % repos, dir
proc gist_clone (repos,dir:string) =
git_clone "https://gist.github.com/$#.git" % repos[repos.rfind("/")+1 .. -1], dir
# https://gist.github.com/8cc9ee26bcf509b5fea5.git
proc bitbucket_clone (repos,dir:string)=
git_clone "git@bitbucket.org:$#.git" % repos, dir
result = newStmtList()
for i in imports:
#echo i
let repo_dir = "repos"/ $i.domain / i.repo
let module = repo_dir / i.module
case i.domain
of github:
createDirCT(repo_dir)
github_clone(i.repo, repo_dir)
of bitbucket:
createDirCT(repo_dir)
bitbucket_clone(i.repo, repo_dir)
else:
continue #shouldnt happen
result.add parseExpr("import \"./$1\"" % module)
when defined(Debug):
echo repr(result)
when isMainModule:
template echoCode (code:expr):stmt =
echo astToStr(code), ": ", code
macro test_parser (xpr,eqs): stmt {.immediate.}=
let res = parse_import(xpr)
result = parseExpr("echoCode(($#,\"$#\",\"$#\") == $#)".format(
res[0],res[1],res[2], eqs.repr
))
when defined(debug): result.repr.echo
## tests that url parses correctly
test_parser github.com/a/b, (github,"a/b","b")
test_parser github.com/a/b/c, (github,"a/b","c")
test_parser bitbucket.org/a/b/c/d, (bitbucket,"a/b","c/d")
#test_parser gist.github.com/u/deadbeef/m, (gisthub,"u/deadbeef","m")
#test_parser hg.bitbucket.org/u/r/m, (bitbuckethg, "u/r", "m")
when isMainModule:
import_repo github.com/fowlmouth/glossolalia/src/glossolalia
echo charMatcher[int]('a','b').repeat(1).match("aaba")
when false:
#TODO this
import_repo github.com/x/y as z
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment