mirror of
https://github.com/dragonheim/gagent.git
synced 2025-04-26 12:48:58 -07:00
[CI SKIP] Refactored project layout per Mark Wolfe Blog : https://www.wolfe.id.au/2020/03/10/how-do-i-structure-my-go-project/
This commit is contained in:
parent
0557021282
commit
a7747040ce
31 changed files with 15 additions and 45 deletions
27
pkg/picol/README.md
Normal file
27
pkg/picol/README.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
# picol.go
|
||||
|
||||
Original http://oldblog.antirez.com/post/picol.html
|
||||
|
||||
Sample use:
|
||||
```golang
|
||||
func CommandPuts(i *picol.Interp, argv []string, pd interface{}) (string, error) {
|
||||
if len(argv) != 2 {
|
||||
return "", fmt.Errorf("Wrong number of args for %s %s", argv[0], argv)
|
||||
}
|
||||
fmt.Println(argv[1])
|
||||
return "", nil
|
||||
}
|
||||
...
|
||||
interp := picol.InitInterp()
|
||||
// add core functions
|
||||
interp.RegisterCoreCommands()
|
||||
// add user function
|
||||
interp.RegisterCommand("puts", CommandPuts, nil)
|
||||
// eval
|
||||
result, err := interp.Eval(string(buf))
|
||||
if err != nil {
|
||||
fmt.Println("ERROR", err, result)
|
||||
} else {
|
||||
fmt.Println(result)
|
||||
}
|
||||
```
|
226
pkg/picol/commands.go
Normal file
226
pkg/picol/commands.go
Normal file
|
@ -0,0 +1,226 @@
|
|||
package picol
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ArityErr(i *Interp, name string, argv []string) error {
|
||||
return fmt.Errorf("wrong number of args for %s %s", name, argv)
|
||||
}
|
||||
|
||||
// CommandMath is the math command for TCL
|
||||
func CommandMath(i *Interp, argv []string, pd interface{}) (string, error) {
|
||||
if len(argv) != 3 {
|
||||
return "", ArityErr(i, argv[0], argv)
|
||||
}
|
||||
a, _ := strconv.Atoi(argv[1])
|
||||
b, _ := strconv.Atoi(argv[2])
|
||||
var c int
|
||||
switch {
|
||||
case argv[0] == "+":
|
||||
c = a + b
|
||||
case argv[0] == "-":
|
||||
c = a - b
|
||||
case argv[0] == "*":
|
||||
c = a * b
|
||||
case argv[0] == "/":
|
||||
c = a / b
|
||||
case argv[0] == ">":
|
||||
if a > b {
|
||||
c = 1
|
||||
}
|
||||
case argv[0] == ">=":
|
||||
if a >= b {
|
||||
c = 1
|
||||
}
|
||||
case argv[0] == "<":
|
||||
if a < b {
|
||||
c = 1
|
||||
}
|
||||
case argv[0] == "<=":
|
||||
if a <= b {
|
||||
c = 1
|
||||
}
|
||||
case argv[0] == "==":
|
||||
if a == b {
|
||||
c = 1
|
||||
}
|
||||
case argv[0] == "!=":
|
||||
if a != b {
|
||||
c = 1
|
||||
}
|
||||
default: // FIXME I hate warnings
|
||||
c = 0
|
||||
}
|
||||
return fmt.Sprintf("%d", c), nil
|
||||
}
|
||||
|
||||
// CommandSet is the set command for TCL
|
||||
func CommandSet(i *Interp, argv []string, pd interface{}) (string, error) {
|
||||
if len(argv) != 3 {
|
||||
return "", ArityErr(i, argv[0], argv)
|
||||
}
|
||||
i.SetVar(argv[1], argv[2])
|
||||
return argv[2], nil
|
||||
}
|
||||
|
||||
// CommandUnset is the unset command for TCL
|
||||
func CommandUnset(i *Interp, argv []string, pd interface{}) (string, error) {
|
||||
if len(argv) != 2 {
|
||||
return "", ArityErr(i, argv[0], argv)
|
||||
}
|
||||
i.UnsetVar(argv[1])
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// CommandIf is the if command for TCL
|
||||
func CommandIf(i *Interp, argv []string, pd interface{}) (string, error) {
|
||||
if len(argv) != 3 && len(argv) != 5 {
|
||||
return "", ArityErr(i, argv[0], argv)
|
||||
}
|
||||
|
||||
result, err := i.Eval(argv[1])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if r, _ := strconv.Atoi(result); r != 0 {
|
||||
return i.Eval(argv[2])
|
||||
} else if len(argv) == 5 {
|
||||
return i.Eval(argv[4])
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CommandWhile is the while command for TCL
|
||||
func CommandWhile(i *Interp, argv []string, pd interface{}) (string, error) {
|
||||
if len(argv) != 3 {
|
||||
return "", ArityErr(i, argv[0], argv)
|
||||
}
|
||||
|
||||
for {
|
||||
result, err := i.Eval(argv[1])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if r, _ := strconv.Atoi(result); r != 0 {
|
||||
result, err := i.Eval(argv[2])
|
||||
switch err {
|
||||
case errContinue, nil:
|
||||
//pass
|
||||
case errBreak:
|
||||
return result, nil
|
||||
default:
|
||||
return result, err
|
||||
}
|
||||
} else {
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CommandRetCodes is a function to get the return codes for TCL
|
||||
func CommandRetCodes(i *Interp, argv []string, pd interface{}) (string, error) {
|
||||
if len(argv) != 1 {
|
||||
return "", ArityErr(i, argv[0], argv)
|
||||
}
|
||||
switch argv[0] {
|
||||
case "break":
|
||||
return "", errBreak
|
||||
case "continue":
|
||||
return "", errContinue
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// CommandCallProc is a function to call proc commands for TCL
|
||||
func CommandCallProc(i *Interp, argv []string, pd interface{}) (string, error) {
|
||||
var x []string
|
||||
|
||||
if pd, ok := pd.([]string); ok {
|
||||
x = pd
|
||||
} else {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
i.callframe = &CallFrame{vars: make(map[string]Var), parent: i.callframe}
|
||||
defer func() { i.callframe = i.callframe.parent }() // remove the called proc callframe
|
||||
|
||||
arity := 0
|
||||
for _, arg := range strings.Split(x[0], " ") {
|
||||
if len(arg) == 0 {
|
||||
continue
|
||||
}
|
||||
arity++
|
||||
i.SetVar(arg, argv[arity])
|
||||
}
|
||||
|
||||
if arity != len(argv)-1 {
|
||||
return "", fmt.Errorf("proc '%s' called with wrong arg num", argv[0])
|
||||
}
|
||||
|
||||
body := x[1]
|
||||
result, err := i.Eval(body)
|
||||
if err == errReturn {
|
||||
err = nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
// CommandProc is a function to register proc commands for TCL
|
||||
func CommandProc(i *Interp, argv []string, pd interface{}) (string, error) {
|
||||
if len(argv) != 4 {
|
||||
return "", ArityErr(i, argv[0], argv)
|
||||
}
|
||||
return "", i.RegisterCommand(argv[1], CommandCallProc, []string{argv[2], argv[3]})
|
||||
}
|
||||
|
||||
// CommandReturn is a function to register return codes for commands for TCL
|
||||
func CommandReturn(i *Interp, argv []string, pd interface{}) (string, error) {
|
||||
if len(argv) != 1 && len(argv) != 2 {
|
||||
return "", ArityErr(i, argv[0], argv)
|
||||
}
|
||||
var r string
|
||||
if len(argv) == 2 {
|
||||
r = argv[1]
|
||||
}
|
||||
return r, errReturn
|
||||
}
|
||||
|
||||
// CommandError is a function to return error codes for commands for TCL
|
||||
func CommandError(i *Interp, argv []string, pd interface{}) (string, error) {
|
||||
if len(argv) != 1 && len(argv) != 2 {
|
||||
return "", ArityErr(i, argv[0], argv)
|
||||
}
|
||||
return "", fmt.Errorf(argv[1])
|
||||
}
|
||||
|
||||
// CommandPuts is a function to print strings for TCL
|
||||
func CommandPuts(i *Interp, argv []string, pd interface{}) (string, error) {
|
||||
if len(argv) != 2 {
|
||||
return "", fmt.Errorf("wrong number of args for %s %s", argv[0], argv)
|
||||
}
|
||||
fmt.Println(argv[1])
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// RegisterCoreCommands is a callable to register TCL commands.
|
||||
func (i *Interp) RegisterCoreCommands() {
|
||||
name := [...]string{"+", "-", "*", "/", ">", ">=", "<", "<=", "==", "!="}
|
||||
for _, n := range name {
|
||||
i.RegisterCommand(n, CommandMath, nil)
|
||||
}
|
||||
i.RegisterCommand("set", CommandSet, nil)
|
||||
i.RegisterCommand("unset", CommandUnset, nil)
|
||||
i.RegisterCommand("if", CommandIf, nil)
|
||||
i.RegisterCommand("while", CommandWhile, nil)
|
||||
i.RegisterCommand("break", CommandRetCodes, nil)
|
||||
i.RegisterCommand("continue", CommandRetCodes, nil)
|
||||
i.RegisterCommand("proc", CommandProc, nil)
|
||||
i.RegisterCommand("return", CommandReturn, nil)
|
||||
i.RegisterCommand("error", CommandError, nil)
|
||||
i.RegisterCommand("puts", CommandPuts, nil)
|
||||
}
|
9
pkg/picol/examples/fib.tcl
Normal file
9
pkg/picol/examples/fib.tcl
Normal file
|
@ -0,0 +1,9 @@
|
|||
proc fib {x} {
|
||||
if {<= $x 1} {
|
||||
return 1
|
||||
} else {
|
||||
+ [fib [- $x 1]] [fib [- $x 2]]
|
||||
}
|
||||
}
|
||||
|
||||
puts [fib 20]
|
15
pkg/picol/examples/t2.tcl
Normal file
15
pkg/picol/examples/t2.tcl
Normal file
|
@ -0,0 +1,15 @@
|
|||
proc square {x} {
|
||||
* $x $x
|
||||
}
|
||||
|
||||
set a 1
|
||||
while {<= $a 10} {
|
||||
if {== $a 5} {
|
||||
puts {Missing five!}
|
||||
set a [+ $a 1]
|
||||
continue
|
||||
}
|
||||
puts "I can compute that $a*$a = [square $a]"
|
||||
set a [+ $a 1]
|
||||
}
|
||||
|
5
pkg/picol/examples/tst.tcl
Normal file
5
pkg/picol/examples/tst.tcl
Normal file
|
@ -0,0 +1,5 @@
|
|||
proc square {x} {
|
||||
* $x $x
|
||||
}
|
||||
|
||||
puts [square 5]
|
250
pkg/picol/parser.go
Normal file
250
pkg/picol/parser.go
Normal file
|
@ -0,0 +1,250 @@
|
|||
package picol
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
ptESC = iota
|
||||
ptSTR
|
||||
ptCMD
|
||||
ptVAR
|
||||
ptSEP
|
||||
ptEOL
|
||||
ptEOF
|
||||
)
|
||||
|
||||
type parserStruct struct {
|
||||
text string
|
||||
p, start, end, ln int
|
||||
insidequote int
|
||||
Type int
|
||||
}
|
||||
|
||||
func initParser(text string) *parserStruct {
|
||||
return &parserStruct{text, 0, 0, 0, len(text), 0, ptEOL}
|
||||
}
|
||||
|
||||
func (p *parserStruct) next() {
|
||||
_, w := utf8.DecodeRuneInString(p.text[p.p:])
|
||||
p.p += w
|
||||
p.ln -= w
|
||||
}
|
||||
|
||||
func (p *parserStruct) current() rune {
|
||||
r, _ := utf8.DecodeRuneInString(p.text[p.p:])
|
||||
return r
|
||||
}
|
||||
|
||||
func (p *parserStruct) token() (t string) {
|
||||
defer recover()
|
||||
return p.text[p.start:p.end]
|
||||
}
|
||||
|
||||
func (p *parserStruct) parseSep() string {
|
||||
p.start = p.p
|
||||
for ; p.p < len(p.text); p.next() {
|
||||
if !unicode.IsSpace(p.current()) {
|
||||
break
|
||||
}
|
||||
}
|
||||
p.end = p.p
|
||||
p.Type = ptSEP
|
||||
return p.token()
|
||||
}
|
||||
|
||||
func (p *parserStruct) parseEol() string {
|
||||
p.start = p.p
|
||||
|
||||
for ; p.p < len(p.text); p.next() {
|
||||
if p.current() == ';' || unicode.IsSpace(p.current()) {
|
||||
// pass
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
p.end = p.p
|
||||
p.Type = ptEOL
|
||||
return p.token()
|
||||
}
|
||||
|
||||
func (p *parserStruct) parseCommand() string {
|
||||
level, blevel := 1, 0
|
||||
p.next() // skip
|
||||
p.start = p.p
|
||||
Loop:
|
||||
for {
|
||||
switch {
|
||||
case p.ln == 0:
|
||||
break Loop
|
||||
case p.current() == '[' && blevel == 0:
|
||||
level++
|
||||
case p.current() == ']' && blevel == 0:
|
||||
level--
|
||||
if level == 0 {
|
||||
break Loop
|
||||
}
|
||||
case p.current() == '\\':
|
||||
p.next()
|
||||
case p.current() == '{':
|
||||
blevel++
|
||||
case p.current() == '}' && blevel != 0:
|
||||
blevel--
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
p.end = p.p
|
||||
p.Type = ptCMD
|
||||
if p.p < len(p.text) && p.current() == ']' {
|
||||
p.next()
|
||||
}
|
||||
return p.token()
|
||||
}
|
||||
|
||||
func (p *parserStruct) parseVar() string {
|
||||
p.next() // skip the $
|
||||
p.start = p.p
|
||||
|
||||
if p.current() == '{' {
|
||||
p.Type = ptVAR
|
||||
return p.parseBrace()
|
||||
}
|
||||
|
||||
for p.p < len(p.text) {
|
||||
c := p.current()
|
||||
if unicode.IsLetter(c) || ('0' <= c && c <= '9') || c == '_' {
|
||||
p.next()
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if p.start == p.p { // It's just a single char string "$"
|
||||
p.start = p.p - 1
|
||||
p.end = p.p
|
||||
p.Type = ptSTR
|
||||
} else {
|
||||
p.end = p.p
|
||||
p.Type = ptVAR
|
||||
}
|
||||
return p.token()
|
||||
}
|
||||
|
||||
func (p *parserStruct) parseBrace() string {
|
||||
level := 1
|
||||
p.next() // skip
|
||||
p.start = p.p
|
||||
|
||||
Loop:
|
||||
for p.p < len(p.text) {
|
||||
c := p.current()
|
||||
switch {
|
||||
case p.ln >= 2 && c == '\\':
|
||||
p.next()
|
||||
case p.ln == 0 || c == '}':
|
||||
level--
|
||||
if level == 0 || p.ln == 0 {
|
||||
break Loop
|
||||
}
|
||||
case c == '{':
|
||||
level++
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
p.end = p.p
|
||||
if p.ln != 0 { // Skip final closed brace
|
||||
p.next()
|
||||
}
|
||||
return p.token()
|
||||
}
|
||||
|
||||
func (p *parserStruct) parseString() string {
|
||||
newword := p.Type == ptSEP || p.Type == ptEOL || p.Type == ptSTR
|
||||
|
||||
if c := p.current(); newword && c == '{' {
|
||||
p.Type = ptSTR
|
||||
return p.parseBrace()
|
||||
} else if newword && c == '"' {
|
||||
p.insidequote = 1
|
||||
p.next() // skip
|
||||
}
|
||||
|
||||
p.start = p.p
|
||||
|
||||
Loop:
|
||||
for ; p.ln != 0; p.next() {
|
||||
switch p.current() {
|
||||
case '\\':
|
||||
if p.ln >= 2 {
|
||||
p.next()
|
||||
}
|
||||
case '$', '[':
|
||||
break Loop
|
||||
case '"':
|
||||
if p.insidequote != 0 {
|
||||
p.end = p.p
|
||||
p.Type = ptESC
|
||||
p.next()
|
||||
p.insidequote = 0
|
||||
return p.token()
|
||||
}
|
||||
}
|
||||
if p.current() == ';' || unicode.IsSpace(p.current()) {
|
||||
if p.insidequote == 0 {
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p.end = p.p
|
||||
p.Type = ptESC
|
||||
return p.token()
|
||||
}
|
||||
|
||||
func (p *parserStruct) parseComment() string {
|
||||
for p.ln != 0 && p.current() != '\n' {
|
||||
p.next()
|
||||
}
|
||||
return p.token()
|
||||
}
|
||||
|
||||
func (p *parserStruct) GetToken() string {
|
||||
for {
|
||||
if p.ln == 0 {
|
||||
if p.Type != ptEOL && p.Type != ptEOF {
|
||||
p.Type = ptEOL
|
||||
} else {
|
||||
p.Type = ptEOF
|
||||
}
|
||||
return p.token()
|
||||
}
|
||||
|
||||
switch p.current() {
|
||||
case ' ', '\t', '\r':
|
||||
if p.insidequote != 0 {
|
||||
return p.parseString()
|
||||
}
|
||||
return p.parseSep()
|
||||
case '\n', ';':
|
||||
if p.insidequote != 0 {
|
||||
return p.parseString()
|
||||
}
|
||||
return p.parseEol()
|
||||
case '[':
|
||||
return p.parseCommand()
|
||||
case '$':
|
||||
return p.parseVar()
|
||||
case '#':
|
||||
if p.Type == ptEOL {
|
||||
p.parseComment()
|
||||
continue
|
||||
}
|
||||
return p.parseString()
|
||||
default:
|
||||
return p.parseString()
|
||||
}
|
||||
}
|
||||
/* return p.token() /* unreached */
|
||||
}
|
138
pkg/picol/picol.go
Normal file
138
pkg/picol/picol.go
Normal file
|
@ -0,0 +1,138 @@
|
|||
package picol
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
errReturn = errors.New("RETURN")
|
||||
errBreak = errors.New("BREAK")
|
||||
errContinue = errors.New("CONTINUE")
|
||||
)
|
||||
|
||||
type Var string
|
||||
type CmdFunc func(i *Interp, argv []string, privdata interface{}) (string, error)
|
||||
type Cmd struct {
|
||||
fn CmdFunc
|
||||
privdata interface{}
|
||||
}
|
||||
type CallFrame struct {
|
||||
vars map[string]Var
|
||||
parent *CallFrame
|
||||
}
|
||||
type Interp struct {
|
||||
level int
|
||||
callframe *CallFrame
|
||||
commands map[string]Cmd
|
||||
}
|
||||
|
||||
func InitInterp() *Interp {
|
||||
return &Interp{
|
||||
level: 0,
|
||||
callframe: &CallFrame{vars: make(map[string]Var)},
|
||||
commands: make(map[string]Cmd),
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Interp) Var(name string) (Var, bool) {
|
||||
for frame := i.callframe; frame != nil; frame = frame.parent {
|
||||
v, ok := frame.vars[name]
|
||||
if ok {
|
||||
return v, ok
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
func (i *Interp) SetVar(name, val string) {
|
||||
i.callframe.vars[name] = Var(val)
|
||||
}
|
||||
|
||||
func (i *Interp) UnsetVar(name string) {
|
||||
delete(i.callframe.vars, name)
|
||||
}
|
||||
|
||||
func (i *Interp) Command(name string) *Cmd {
|
||||
v, ok := i.commands[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return &v
|
||||
}
|
||||
|
||||
func (i *Interp) RegisterCommand(name string, fn CmdFunc, privdata interface{}) error {
|
||||
c := i.Command(name)
|
||||
if c != nil {
|
||||
return fmt.Errorf("Command '%s' already defined", name)
|
||||
}
|
||||
|
||||
i.commands[name] = Cmd{fn, privdata}
|
||||
return nil
|
||||
}
|
||||
|
||||
/* EVAL! */
|
||||
func (i *Interp) Eval(t string) (string, error) {
|
||||
p := initParser(t)
|
||||
var result string
|
||||
var err error
|
||||
|
||||
argv := []string{}
|
||||
|
||||
for {
|
||||
prevtype := p.Type
|
||||
// XXX
|
||||
t = p.GetToken()
|
||||
if p.Type == ptEOF {
|
||||
break
|
||||
}
|
||||
|
||||
switch p.Type {
|
||||
case ptVAR:
|
||||
v, ok := i.Var(t)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("no such variable '%s'", t)
|
||||
}
|
||||
t = string(v)
|
||||
case ptCMD:
|
||||
result, err = i.Eval(t)
|
||||
if err != nil {
|
||||
return result, err
|
||||
} else {
|
||||
t = result
|
||||
}
|
||||
case ptESC:
|
||||
// XXX: escape handling missing!
|
||||
case ptSEP:
|
||||
prevtype = p.Type
|
||||
continue
|
||||
}
|
||||
|
||||
// We have a complete command + args. Call it!
|
||||
if p.Type == ptEOL {
|
||||
prevtype = p.Type
|
||||
if len(argv) != 0 {
|
||||
c := i.Command(argv[0])
|
||||
if c == nil {
|
||||
return "", fmt.Errorf("no such command '%s'", argv[0])
|
||||
}
|
||||
result, err = c.fn(i, argv, c.privdata)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
// Prepare for the next command
|
||||
argv = []string{}
|
||||
continue
|
||||
}
|
||||
|
||||
// We have a new token, append to the previous or as new arg?
|
||||
if prevtype == ptSEP || prevtype == ptEOL {
|
||||
argv = append(argv, t)
|
||||
} else { // Interpolation
|
||||
argv[len(argv)-1] = strings.Join([]string{argv[len(argv)-1], t}, "")
|
||||
}
|
||||
prevtype = p.Type
|
||||
}
|
||||
return result, nil
|
||||
}
|
47
pkg/picol/picol_unused/main.go_unused
Normal file
47
pkg/picol/picol_unused/main.go_unused
Normal file
|
@ -0,0 +1,47 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
picol "git.dragonheim.net/dragonheim/gagent/src/picol"
|
||||
)
|
||||
|
||||
var fname = flag.String("f", "", "file name")
|
||||
|
||||
// CommandPuts is a simple version of the TCL puts function.
|
||||
func CommandPuts(i *picol.Interp, argv []string, pd interface{}) (string, error) {
|
||||
if len(argv) != 2 {
|
||||
return "", fmt.Errorf("wrong number of args for %s %s", argv[0], argv)
|
||||
}
|
||||
fmt.Println(argv[1])
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
interp := picol.InitInterp()
|
||||
interp.RegisterCoreCommands()
|
||||
interp.RegisterCommand("puts", CommandPuts, nil)
|
||||
|
||||
buf, err := ioutil.ReadFile(*fname)
|
||||
if err == nil {
|
||||
result, err := interp.Eval(string(buf))
|
||||
if err != nil {
|
||||
fmt.Println("ERRROR", result, err)
|
||||
}
|
||||
} else {
|
||||
for {
|
||||
fmt.Print("picol> ")
|
||||
scanner := bufio.NewReader(os.Stdin)
|
||||
clibuf, _ := scanner.ReadString('\n')
|
||||
result, err := interp.Eval(clibuf[:len(clibuf)-1])
|
||||
if len(result) != 0 {
|
||||
fmt.Println("ERRROR", result, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue