Skip to content

Commit

Permalink
linter: resolve standard symbols
Browse files Browse the repository at this point in the history
  • Loading branch information
candid82 committed Jan 16, 2017
1 parent 92499c2 commit af694b1
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 31 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ bindata.go
play
.vscode
.idea

core/core_data.go
core/a_core_data.go
core/a_linter_data.go
9 changes: 9 additions & 0 deletions core/data/linter.joke
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
;; This vars are declared for the linter mode to work properly
(def ^:private defmulti)
(def ^:private defmethod)
(def ^:private defprotocol)
(def ^:private defrecord)
(def ^:private defproject)
(def ^:private derive)
(def ^:private alter-var-root)
(def ^:private Exception)
31 changes: 19 additions & 12 deletions core/gen_data/gen_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,35 @@ import (
"strings"
)

var coreTemplate string = `// Generated by gen_data. Don't modify manually!
var template string = `// Generated by gen_data. Don't modify manually!
package core
var coreData = []byte("{content}")
var {name}Data = []byte("{content}")
`

const hextable = "0123456789abcdef"

func main() {

coreContent, err := ioutil.ReadFile("data/core.joke")
files, err := ioutil.ReadDir("data")
if err != nil {
panic(err)
}
dst := make([]byte, len(coreContent)*4)
for i, v := range coreContent {
dst[i*4] = '\\'
dst[i*4+1] = 'x'
dst[i*4+2] = hextable[v>>4]
dst[i*4+3] = hextable[v&0x0f]
for _, f := range files {
content, err := ioutil.ReadFile("data/" + f.Name())
if err != nil {
panic(err)
}
dst := make([]byte, len(content)*4)
for i, v := range content {
dst[i*4] = '\\'
dst[i*4+1] = 'x'
dst[i*4+2] = hextable[v>>4]
dst[i*4+3] = hextable[v&0x0f]
}
name := f.Name()[0 : len(f.Name())-5] // assumes .joke extension
fileContent := strings.Replace(template, "{name}", name, 1)
fileContent = strings.Replace(fileContent, "{content}", string(dst), 1)
ioutil.WriteFile("a_"+name+"_data.go", []byte(fileContent), 0666)
}

ioutil.WriteFile("core_data.go", []byte(strings.Replace(coreTemplate, "{content}", string(dst), 1)), 0666)
}
43 changes: 34 additions & 9 deletions core/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package core
import (
"fmt"
"os"
"strings"
"unsafe"
)

Expand Down Expand Up @@ -130,11 +131,12 @@ type (
frame int
}
ParseContext struct {
GlobalEnv *Env
localBindings *Bindings
loopBindings [][]Symbol
recur bool
noRecurAllowed bool
GlobalEnv *Env
localBindings *Bindings
loopBindings [][]Symbol
recur bool
noRecurAllowed bool
isUnknownCallableScope bool
}
)

Expand Down Expand Up @@ -822,6 +824,15 @@ func parseSetMacro(obj Object, ctx *ParseContext) Expr {
panic(&ParseError{obj: obj, msg: "set-macro* argument must be a var"})
}

func isUnknownCallable(expr Expr) bool {
switch c := expr.(type) {
case *VarRefExpr:
return c.vr.Value == nil
default:
return false
}
}

func parseList(obj Object, ctx *ParseContext) Expr {
expanded := macroexpand1(obj.(Seq), ctx)
if expanded != obj {
Expand Down Expand Up @@ -899,8 +910,16 @@ func parseList(obj Object, ctx *ParseContext) Expr {
return parseTry(obj, ctx)
}
}
callable := Parse(first, ctx)
if isUnknownCallable(callable) {
t := ctx.isUnknownCallableScope
ctx.isUnknownCallableScope = true
defer func() {
ctx.isUnknownCallableScope = t
}()
}
res := &CallExpr{
callable: Parse(first, ctx),
callable: callable,
args: parseSeq(seq.Rest(), ctx),
Position: pos,
name: "fn",
Expand Down Expand Up @@ -957,6 +976,10 @@ func internFakeSymbol(sym Symbol, ctx *ParseContext) *Var {
return ctx.GlobalEnv.CurrentNamespace().Intern(MakeSymbol(ns + *sym.name))
}

func isInteropSymbol(sym Symbol) bool {
return sym.ns == nil && (strings.HasPrefix(*sym.name, ".") || strings.HasSuffix(*sym.name, "."))
}

func parseSymbol(obj Object, ctx *ParseContext) Expr {
sym := obj.(Symbol)
b := ctx.GetLocalBinding(sym)
Expand All @@ -977,9 +1000,11 @@ func parseSymbol(obj Object, ctx *ParseContext) Expr {
if !LINTER_MODE {
panic(&ParseError{obj: obj, msg: "Unable to resolve symbol: " + sym.ToString(false)})
} else {
symNs := ctx.GlobalEnv.NamespaceFor(ctx.GlobalEnv.CurrentNamespace(), sym)
if symNs == nil || symNs == ctx.GlobalEnv.CurrentNamespace() {
fmt.Fprintln(os.Stderr, &ParseError{obj: obj, msg: "Unable to resolve symbol: " + sym.ToString(false)})
if !isInteropSymbol(sym) && !ctx.isUnknownCallableScope {
symNs := ctx.GlobalEnv.NamespaceFor(ctx.GlobalEnv.CurrentNamespace(), sym)
if symNs == nil || symNs == ctx.GlobalEnv.CurrentNamespace() {
fmt.Fprintln(os.Stderr, &ParseError{obj: obj, msg: "Unable to resolve symbol: " + sym.ToString(false)})
}
}
vr = internFakeSymbol(sym, ctx)
}
Expand Down
19 changes: 14 additions & 5 deletions core/procs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1301,6 +1301,19 @@ func intern(name string, proc Proc) {
vr.meta = privateMeta
}

func processData(data []byte) {
currentNamespace := GLOBAL_ENV.ns.Value
GLOBAL_ENV.ns.Value = GLOBAL_ENV.CoreNamespace
reader := bytes.NewReader(data)
ProcessReader(NewReader(reader, "<core>"), "", EVAL)
GLOBAL_ENV.ns.Value = currentNamespace
}

func ProcessLinterData() {
reader := bytes.NewReader(linterData)
ProcessReader(NewReader(reader, "<user>"), "", EVAL)
}

func init() {
rand.Seed(time.Now().UnixNano())
GLOBAL_ENV.CoreNamespace.InternVar("*assert*", Bool{B: true},
Expand Down Expand Up @@ -1452,9 +1465,5 @@ func init() {
intern("index-of*", procIndexOf)
intern("lib-path*", procLibPath)

currentNamespace := GLOBAL_ENV.ns.Value
GLOBAL_ENV.ns.Value = GLOBAL_ENV.CoreNamespace
reader := bytes.NewReader(coreData)
ProcessReader(NewReader(reader, "<core>"), "", EVAL)
GLOBAL_ENV.ns.Value = currentNamespace
processData(coreData)
}
11 changes: 8 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ func repl(phase Phase) {
}
}

func configureLinterMode() {
ProcessLinterData()
LINTER_MODE = true
lm, _ := GLOBAL_ENV.Resolve(MakeSymbol("core/*linter-mode*"))
lm.Value = Bool{B: true}
}

func main() {
GLOBAL_ENV.FindNamespace(MakeSymbol("user")).ReferAll(GLOBAL_ENV.FindNamespace(MakeSymbol("core")))
if len(os.Args) == 1 {
Expand All @@ -165,9 +172,7 @@ func main() {
case "--read":
processFile(os.Args[2], READ)
case "--parse":
LINTER_MODE = true
lm, _ := GLOBAL_ENV.Resolve(MakeSymbol("core/*linter-mode*"))
lm.Value = Bool{B: true}
configureLinterMode()
processFile(os.Args[2], PARSE)
default:
processFile(os.Args[1], EVAL)
Expand Down
4 changes: 4 additions & 0 deletions tests/symbols-lint.joke
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
[tests.ext2 :as ext2]
[tests.ext3 :as ext3 :refer [e3]]))



(def f [])

(f 1)
Expand All @@ -16,3 +18,5 @@
(tt/g 3)

(ext2/g 4)

(defprotocol Person)

0 comments on commit af694b1

Please sign in to comment.