Skip to content
Permalink
Browse files

Move language core out to separate Go package

  • Loading branch information...
thesephist committed Aug 8, 2019
1 parent a8326c3 commit 843166173c107830c1f0bf03a224e3756f1e192c
Showing with 92 additions and 75 deletions.
  1. +5 −5 .gitignore
  2. +6 −5 Makefile
  3. +30 −18 README.md
  4. +11 −6 main.go → cmd/ink.go
  5. +1 −1 { → pkg/ink}/error.go
  6. +12 −12 { → pkg/ink}/eval.go
  7. +4 −4 { → pkg/ink}/lexer.go
  8. +12 −12 { → pkg/ink}/log.go
  9. +5 −5 { → pkg/ink}/parser.go
  10. +2 −2 { → pkg/ink}/runtime.go
  11. +4 −5 samples/io.ink
@@ -1,9 +1,9 @@
# Build artifacts
ink
ink-*
ink.exe
ink.exe~
ink.wasm
./ink
./ink-*
./ink.exe
./ink.exe~
./ink.wasm
*.dll
*.o
*.so
@@ -1,4 +1,5 @@
RUN = go run -race .
CMD = ./cmd/ink.go
RUN = go run -race ${CMD}
LDFLAGS = -ldflags="-s -w"

all: run test install
@@ -44,7 +45,7 @@ test:

# build for specific OS target
build-%:
GOOS=$* GOARCH=amd64 go build ${LDFLAGS} -o ink-$*
GOOS=$* GOARCH=amd64 go build ${LDFLAGS} -o ink-$* ${CMD}


# build for all OS targets, useful for releases
@@ -54,14 +55,14 @@ build: build-linux build-darwin build-windows build-openbsd
# install on host system
install:
cp utils/ink.vim ~/.vim/syntax/ink.vim
go install ${LDFLAGS}
go install ${LDFLAGS} ${CMD}
ls -l `which ink`


# pre-commit hook
precommit:
go vet .
go fmt .
go vet ./cmd ./pkg/ink
go fmt ./cmd ./pkg/ink


# clean any generated files
@@ -156,34 +156,46 @@ The APIs are still in development / in flux, but you can check out `main.go` and
For now, here's a minimal example of creating an execution context for Ink and running some Ink code from stdin. (In fact, this is very nearly the implementation of executing from stdin in the interpreter.)

```go
package main
import (
"github.com/thesephist/ink/pkg/ink"
)
func main() {
// Create an "Engine", which is a global execution context for the lifetime of an Ink program.
eng := Engine{}
// Create a "Context", which is a temporary execution context for a given source of input.
ctx := eng.CreateContext{}
// Execute code from an io.Reader
ctx.Exec(os.Stdin)
// Wait until all concurrent callbacks finish from the program before exiting
eng.Listeners.Wait()
// Create an "Engine", which is a global execution context for the lifetime of an Ink program.
eng := ink.Engine{}
// Create a "Context", which is a temporary execution context for a given source of input.
ctx := eng.CreateContext{}
// Execute code from an io.Reader
ctx.Exec(os.Stdin)
// Wait until all concurrent callbacks finish from the program before exiting
eng.Listeners.Wait()
}
```

To run from a file, use `os.File` as an `io.Reader`.

```go
package main
import (
"github.com/thesephist/ink/pkg/ink"
)
func main() {
eng := Engine{}
ctx := eng.CreateContext{}
eng := ink.Engine{}
ctx := eng.CreateContext{}
file, err := os.Open("main.ink")
defer file.Close()
if err != nil {
log.Fatal("Could not open main.ink for execution")
}
file, err := os.Open("main.ink")
defer file.Close()
if err != nil {
log.Fatal("Could not open main.ink for execution")
}
ctx.Exec(file)
eng.Listeners.Wait()
ctx.Exec(file)
eng.Listeners.Wait()
}
```

@@ -8,6 +8,8 @@ import (
"os"
"path"
"strings"

"github.com/thesephist/ink/pkg/ink"
)

const VERSION = "0.1.5"
@@ -67,14 +69,14 @@ func main() {
}

// execution environment
eng := Engine{
eng := ink.Engine{
FatalError: false,
Permissions: PermissionsConfig{
Permissions: ink.PermissionsConfig{
Read: !*noRead && !*isolate,
Write: !*noWrite && !*isolate,
Net: !*noNet && !*isolate,
},
Debug: DebugConfig{
Debug: ink.DebugConfig{
Lex: *debugLexer || *verbose,
Parse: *debugParser || *verbose,
Dump: *dump || *verbose,
@@ -90,13 +92,16 @@ func main() {
replLoop:
for {
// green arrow
fmt.Printf(ANSI_GREEN_BOLD + "> " + ANSI_RESET)
fmt.Printf(ink.ANSI_GREEN_BOLD + "> " + ink.ANSI_RESET)
text, err := reader.ReadString('\n')

if err == io.EOF {
break
} else if err != nil {
logErrf(ErrSystem, "unexpected end to input:\n\t-> %s", err.Error())
ink.LogErrf(
ink.ErrSystem,
"unexpected end to input:\n\t-> %s", err.Error(),
)
}

switch {
@@ -112,7 +117,7 @@ func main() {
default:
val, _ := ctx.Exec(strings.NewReader(text))
if val != nil {
logInteractive(val.String())
ink.LogInteractive(val.String())
}
}
}
@@ -1,4 +1,4 @@
package main
package ink

// Error reasons are enumerated here to be used in the Err struct,
// the error type shared across all Ink APIs.
@@ -1,4 +1,4 @@
package main
package ink

import (
"bytes"
@@ -267,7 +267,7 @@ func (n UnaryExprNode) Eval(frame *StackFrame, allowThunk bool) (Value, error) {
}
}

logErrf(ErrAssert, "unrecognized unary operator %s", n)
LogErrf(ErrAssert, "unrecognized unary operator %s", n)
return nil, nil
}

@@ -670,7 +670,7 @@ func (n BinaryExprNode) Eval(frame *StackFrame, allowThunk bool) (Value, error)
return BooleanValue(leftValue.Equals(rightValue)), nil
}

logErrf(ErrAssert, "unknown binary operator %s", n.String())
LogErrf(ErrAssert, "unknown binary operator %s", n.String())
return nil, err
}

@@ -725,7 +725,7 @@ func evalInkFunction(fn Value, allowThunk bool, args ...Value) (Value, error) {
}

func (n MatchClauseNode) Eval(frame *StackFrame, allowThunk bool) (Value, error) {
logErrf(ErrAssert, "cannot Eval a MatchClauseNode")
LogErrf(ErrAssert, "cannot Eval a MatchClauseNode")
return nil, nil
}

@@ -823,7 +823,7 @@ func (n ObjectLiteralNode) Eval(frame *StackFrame, allowThunk bool) (Value, erro
}

func (n ObjectEntryNode) Eval(frame *StackFrame, allowThunk bool) (Value, error) {
logErrf(ErrAssert, "cannot Eval an ObjectEntryNode")
LogErrf(ErrAssert, "cannot Eval an ObjectEntryNode")
return nil, nil
}

@@ -889,7 +889,7 @@ func (frame *StackFrame) Up(name string, val Value) {
frame = frame.parent
}

logErrf(
LogErrf(
ErrAssert,
fmt.Sprintf("StackFrame.Up expected to find variable '%s' in frame but did not",
name),
@@ -961,9 +961,9 @@ func (ctx *Context) LogErr(e Err) {
}

if ctx.Engine.FatalError {
logErr(e.reason, msg)
LogErr(e.reason, msg)
} else {
logSafeErr(e.reason, msg)
LogSafeErr(e.reason, msg)
}
}

@@ -984,14 +984,14 @@ type DebugConfig struct {

// Dump prints the current state of the Context's global heap
func (ctx *Context) Dump() {
logDebug("frame dump ->", ctx.Frame.String())
LogDebug("frame dump ->", ctx.Frame.String())
}

func (ctx *Context) resetWd() {
var err error
ctx.Cwd, err = os.Getwd()
if err != nil {
logErrf(
LogErrf(
ErrSystem,
"could not identify current working directory\n\t-> %s", err,
)
@@ -1053,7 +1053,7 @@ func (ctx *Context) Exec(input io.Reader) (Value, error) {
// ExecPath is a convenience function to Exec() a program file in a given Context.
func (ctx *Context) ExecPath(filePath string) {
if !path.IsAbs(filePath) {
logErrf(
LogErrf(
ErrAssert,
"Context.ExecPath expected an absolute path, got something else",
)
@@ -1066,7 +1066,7 @@ func (ctx *Context) ExecPath(filePath string) {
file, err := os.Open(filePath)
defer file.Close()
if err != nil {
logSafeErr(
LogSafeErr(
ErrSystem,
fmt.Sprintf("could not open %s for execution:\n\t-> %s", filePath, err),
)
@@ -1,4 +1,4 @@
package main
package ink

import (
"bufio"
@@ -127,7 +127,7 @@ func Tokenize(
simpleCommit := func(tok Tok) {
lastKind = tok.kind
if debugLexer {
logDebug("lex ->", tok.String())
LogDebug("lex ->", tok.String())
}
tokens <- tok
}
@@ -156,9 +156,9 @@ func Tokenize(
lineNo, colNo, err.Error()),
}
if fatalError {
logErr(e.reason, e.message)
LogErr(e.reason, e.message)
} else {
logSafeErr(e.reason, e.message)
LogSafeErr(e.reason, e.message)
}
}
simpleCommit(Tok{
@@ -1,4 +1,4 @@
package main
package ink

import (
"fmt"
@@ -18,23 +18,23 @@ const (
ANSI_RED_BOLD = ""
)

func logDebug(args ...string) {
func LogDebug(args ...string) {
fmt.Println(ANSI_BLUE_BOLD + "debug: " + ANSI_BLUE + strings.Join(args, " ") + ANSI_RESET)
}

func logDebugf(s string, args ...interface{}) {
logDebug(fmt.Sprintf(s, args...))
func LogDebugf(s string, args ...interface{}) {
LogDebug(fmt.Sprintf(s, args...))
}

func logInteractive(args ...string) {
func LogInteractive(args ...string) {
fmt.Println(ANSI_GREEN + strings.Join(args, " ") + ANSI_RESET)
}

func logInteractivef(s string, args ...interface{}) {
logInteractive(fmt.Sprintf(s, args...))
func LogInteractivef(s string, args ...interface{}) {
LogInteractive(fmt.Sprintf(s, args...))
}

func logSafeErr(reason int, args ...string) {
func LogSafeErr(reason int, args ...string) {
errStr := "error"
switch reason {
case ErrSyntax:
@@ -51,11 +51,11 @@ func logSafeErr(reason int, args ...string) {
fmt.Fprintln(os.Stderr, ANSI_RED_BOLD+errStr+": "+ANSI_RED+strings.Join(args, " ")+ANSI_RESET)
}

func logErr(reason int, args ...string) {
logSafeErr(reason, args...)
func LogErr(reason int, args ...string) {
LogSafeErr(reason, args...)
os.Exit(reason)
}

func logErrf(reason int, s string, args ...interface{}) {
logErr(reason, fmt.Sprintf(s, args...))
func LogErrf(reason int, s string, args ...interface{}) {
LogErr(reason, fmt.Sprintf(s, args...))
}
@@ -1,4 +1,4 @@
package main
package ink

import (
"fmt"
@@ -289,19 +289,19 @@ func Parse(
e, isErr := err.(Err)
if isErr {
if fatalError {
logErr(e.reason, e.message)
LogErr(e.reason, e.message)
} else {
logSafeErr(e.reason, e.message)
LogSafeErr(e.reason, e.message)
}
} else {
logErrf(ErrAssert, "err raised that was not of Err type -> %s",
LogErrf(ErrAssert, "err raised that was not of Err type -> %s",
err.Error())
}
return
}

if debugParser {
logDebug("parse ->", expr.String())
LogDebug("parse ->", expr.String())
}
nodes <- expr
}
@@ -1,4 +1,4 @@
package main
package ink

import (
"bufio"
@@ -1090,7 +1090,7 @@ func inkWait(ctx *Context, in []Value) (Value, error) {
if e, isErr := err.(Err); isErr {
ctx.LogErr(e)
} else {
logErrf(ErrAssert, "Eval of an Ink node returned error not of type Err")
LogErrf(ErrAssert, "Eval of an Ink node returned error not of type Err")
}
}
})

0 comments on commit 8431661

Please sign in to comment.
You can’t perform that action at this time.