Compare commits
7 Commits
d643e24a1b
...
54bc759f70
Author | SHA1 | Date | |
---|---|---|---|
54bc759f70 | |||
b6887af77a | |||
353d495c50 | |||
f45b2c0a88 | |||
624e3ac0f2 | |||
35fcbd2bce | |||
2150181303 |
@ -25,7 +25,8 @@ func TestExpr(t *testing.T) {
|
|||||||
failed := 0
|
failed := 0
|
||||||
|
|
||||||
inputs1 := []inputType{
|
inputs1 := []inputType{
|
||||||
{`f = func(op){op()}; f(func(){2})`, int64(2), nil},
|
{`f=openFile("/tmp/test2.txt"); line=readFile(f); closeFile(f); line`, "ciao", nil},
|
||||||
|
//{`f = func(op){op()}; f(func(){2})`, int64(2), nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, input := range inputs1 {
|
for i, input := range inputs1 {
|
||||||
@ -36,6 +37,7 @@ func TestExpr(t *testing.T) {
|
|||||||
ctx := NewSimpleFuncStore()
|
ctx := NewSimpleFuncStore()
|
||||||
// ImportMathFuncs(ctx)
|
// ImportMathFuncs(ctx)
|
||||||
// ImportImportFunc(ctx)
|
// ImportImportFunc(ctx)
|
||||||
|
ImportOsFuncs(ctx)
|
||||||
parser := NewParser(ctx)
|
parser := NewParser(ctx)
|
||||||
|
|
||||||
logTest(t, i+1, input.source, input.wantResult, input.wantErr)
|
logTest(t, i+1, input.source, input.wantResult, input.wantErr)
|
||||||
|
@ -136,7 +136,7 @@ func doImport(ctx ExprContext, name string, dirList []string, it Iterator) (resu
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ImportImportFunc(ctx ExprContext) {
|
func ImportImportFuncs(ctx ExprContext) {
|
||||||
ctx.RegisterFunc("import", &simpleFunctor{f: importFunc}, 1, -1)
|
ctx.RegisterFunc("import", &simpleFunctor{f: importFunc}, 1, -1)
|
||||||
ctx.RegisterFunc("include", &simpleFunctor{f: includeFunc}, 1, -1)
|
ctx.RegisterFunc("include", &simpleFunctor{f: includeFunc}, 1, -1)
|
||||||
}
|
}
|
||||||
|
164
func-os.go
Normal file
164
func-os.go
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// func-os.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type osHandle interface {
|
||||||
|
getFile() *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
type osWriter struct {
|
||||||
|
fh *os.File
|
||||||
|
writer *bufio.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *osWriter) getFile() *os.File {
|
||||||
|
return h.fh
|
||||||
|
}
|
||||||
|
|
||||||
|
type osReader struct {
|
||||||
|
fh *os.File
|
||||||
|
reader *bufio.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *osReader) getFile() *os.File {
|
||||||
|
return h.fh
|
||||||
|
}
|
||||||
|
|
||||||
|
func createFileFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||||
|
var filePath string
|
||||||
|
if len(args) > 0 {
|
||||||
|
filePath, _ = args[0].(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(filePath) > 0 {
|
||||||
|
var fh *os.File
|
||||||
|
if fh, err = os.Create(filePath); err == nil {
|
||||||
|
result = &osWriter{fh: fh, writer: bufio.NewWriter(fh)}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("%s(): missing the file path", name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func openFileFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||||
|
var filePath string
|
||||||
|
if len(args) > 0 {
|
||||||
|
filePath, _ = args[0].(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(filePath) > 0 {
|
||||||
|
var fh *os.File
|
||||||
|
if fh, err = os.Open(filePath); err == nil {
|
||||||
|
result = &osReader{fh: fh, reader: bufio.NewReader(fh)}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("%s(): missing the file path", name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendFileFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||||
|
var filePath string
|
||||||
|
if len(args) > 0 {
|
||||||
|
filePath, _ = args[0].(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(filePath) > 0 {
|
||||||
|
var fh *os.File
|
||||||
|
if fh, err = os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0660); err == nil {
|
||||||
|
result = &osWriter{fh: fh, writer: bufio.NewWriter(fh)}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("%s(): missing the file path", name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeFileFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||||
|
var handle osHandle
|
||||||
|
|
||||||
|
if len(args) > 0 {
|
||||||
|
handle, _ = args[0].(osHandle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if handle != nil {
|
||||||
|
if fh := handle.getFile(); fh != nil {
|
||||||
|
if w, ok := handle.(*osWriter); ok {
|
||||||
|
err = w.writer.Flush()
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
err = fh.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("%s(): invalid file handle", name)
|
||||||
|
}
|
||||||
|
result = err == nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeFileFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||||
|
var handle osHandle
|
||||||
|
|
||||||
|
if len(args) > 0 {
|
||||||
|
handle, _ = args[0].(osHandle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if handle != nil {
|
||||||
|
if fh := handle.getFile(); fh != nil {
|
||||||
|
if w, ok := handle.(*osWriter); ok {
|
||||||
|
result, err = fmt.Fprint(w.writer, args[1:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func readFileFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||||
|
var handle osHandle
|
||||||
|
|
||||||
|
if len(args) > 0 {
|
||||||
|
handle, _ = args[0].(osHandle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if handle != nil {
|
||||||
|
if fh := handle.getFile(); fh != nil {
|
||||||
|
if r, ok := handle.(*osReader); ok {
|
||||||
|
var limit byte = '\n'
|
||||||
|
var v string
|
||||||
|
if len(args) > 1 {
|
||||||
|
if s, ok := args[1].(string); ok && len(s) > 0 {
|
||||||
|
limit = s[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v, err = r.reader.ReadString(limit); err == nil || err == io.EOF {
|
||||||
|
if len(v) > 0 && v[len(v)-1] == limit {
|
||||||
|
result = v[0 : len(v)-1]
|
||||||
|
} else {
|
||||||
|
result = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImportOsFuncs(ctx ExprContext) {
|
||||||
|
ctx.RegisterFunc("openFile", &simpleFunctor{f: openFileFunc}, 1, 1)
|
||||||
|
ctx.RegisterFunc("appendFile", &simpleFunctor{f: appendFileFunc}, 1, 1)
|
||||||
|
ctx.RegisterFunc("createFile", &simpleFunctor{f: createFileFunc}, 1, 1)
|
||||||
|
ctx.RegisterFunc("writeFile", &simpleFunctor{f: writeFileFunc}, 1, -1)
|
||||||
|
ctx.RegisterFunc("readFile", &simpleFunctor{f: readFileFunc}, 1, 2)
|
||||||
|
ctx.RegisterFunc("closeFile", &simpleFunctor{f: closeFileFunc}, 1, 1)
|
||||||
|
}
|
66
operator-insert.go
Normal file
66
operator-insert.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operator-insert.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
|
||||||
|
//-------- insert term
|
||||||
|
|
||||||
|
func newInsertTerm(tk *Token) (inst *term) {
|
||||||
|
return &term{
|
||||||
|
tk: *tk,
|
||||||
|
children: make([]*term, 0, 2),
|
||||||
|
position: posInfix,
|
||||||
|
priority: priSign,
|
||||||
|
evalFunc: evalInsert,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAppendTerm(tk *Token) (inst *term) {
|
||||||
|
return &term{
|
||||||
|
tk: *tk,
|
||||||
|
children: make([]*term, 0, 2),
|
||||||
|
position: posInfix,
|
||||||
|
priority: priSign,
|
||||||
|
evalFunc: evalAppend,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalInsert(ctx ExprContext, self *term) (v any, err error) {
|
||||||
|
var leftValue, rightValue any
|
||||||
|
|
||||||
|
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isList(rightValue) {
|
||||||
|
list, _ := rightValue.([]any)
|
||||||
|
v = append([]any{leftValue}, list...)
|
||||||
|
} else {
|
||||||
|
err = self.errIncompatibleType(rightValue)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalAppend(ctx ExprContext, self *term) (v any, err error) {
|
||||||
|
var leftValue, rightValue any
|
||||||
|
|
||||||
|
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isList(leftValue) {
|
||||||
|
list, _ := leftValue.([]any)
|
||||||
|
v = append(list, rightValue)
|
||||||
|
} else {
|
||||||
|
err = self.errIncompatibleType(leftValue)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
func init() {
|
||||||
|
registerTermConstructor(SymInsert, newInsertTerm)
|
||||||
|
registerTermConstructor(SymAppend, newAppendTerm)
|
||||||
|
}
|
44
operator-length.go
Normal file
44
operator-length.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operator-length.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
//-------- length term
|
||||||
|
|
||||||
|
func newLengthTerm(tk *Token) (inst *term) {
|
||||||
|
return &term{
|
||||||
|
tk: *tk,
|
||||||
|
children: make([]*term, 0, 1),
|
||||||
|
position: posPrefix,
|
||||||
|
priority: priSign,
|
||||||
|
evalFunc: evalLength,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalLength(ctx ExprContext, self *term) (v any, err error) {
|
||||||
|
var rightValue any
|
||||||
|
|
||||||
|
if rightValue, err = self.evalPrefix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isList(rightValue) {
|
||||||
|
list, _ := rightValue.([]any)
|
||||||
|
v = len(list)
|
||||||
|
} else if isString(rightValue) {
|
||||||
|
s, _ := rightValue.(string)
|
||||||
|
v = len(s)
|
||||||
|
// } else {
|
||||||
|
// v = 1
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
err = self.errIncompatibleType(rightValue)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
func init() {
|
||||||
|
registerTermConstructor(SymHash, newLengthTerm)
|
||||||
|
}
|
@ -65,9 +65,7 @@ func evalPlus(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
|
|
||||||
func newMinusTerm(tk *Token) (inst *term) {
|
func newMinusTerm(tk *Token) (inst *term) {
|
||||||
return &term{
|
return &term{
|
||||||
tk: *tk,
|
tk: *tk,
|
||||||
// class: classOperator,
|
|
||||||
// kind: kindUnknown,
|
|
||||||
children: make([]*term, 0, 2),
|
children: make([]*term, 0, 2),
|
||||||
position: posInfix,
|
position: posInfix,
|
||||||
priority: priSum,
|
priority: priSum,
|
||||||
|
@ -191,10 +191,11 @@ func (self *parser) Parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, e
|
|||||||
func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef bool, termSymbols ...Symbol) (tree *ast, err error) {
|
func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef bool, termSymbols ...Symbol) (tree *ast, err error) {
|
||||||
var selectorTerm *term = nil
|
var selectorTerm *term = nil
|
||||||
var currentTerm *term = nil
|
var currentTerm *term = nil
|
||||||
|
var tk *Token
|
||||||
tree = NewAst()
|
tree = NewAst()
|
||||||
firstToken := true
|
firstToken := true
|
||||||
lastSym := SymUnknown
|
lastSym := SymUnknown
|
||||||
for tk := scanner.Next(); err == nil && tk != nil && !tk.IsTerm(termSymbols); tk = scanner.Next() {
|
for tk = scanner.Next(); err == nil && tk != nil && !tk.IsTerm(termSymbols); tk = scanner.Next() {
|
||||||
if tk.Sym == SymComment {
|
if tk.Sym == SymComment {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -281,6 +282,9 @@ func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef
|
|||||||
}
|
}
|
||||||
lastSym = tk.Sym
|
lastSym = tk.Sym
|
||||||
}
|
}
|
||||||
|
if err == nil {
|
||||||
|
err = tk.Error()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ func TestParser(t *testing.T) {
|
|||||||
ctx.SetVar("var1", int64(123))
|
ctx.SetVar("var1", int64(123))
|
||||||
ctx.SetVar("var2", "abc")
|
ctx.SetVar("var2", "abc")
|
||||||
ImportMathFuncs(ctx)
|
ImportMathFuncs(ctx)
|
||||||
ImportImportFunc(ctx)
|
ImportImportFuncs(ctx)
|
||||||
parser := NewParser(ctx)
|
parser := NewParser(ctx)
|
||||||
|
|
||||||
logTest(t, i+1, input.source, input.wantResult, input.wantErr)
|
logTest(t, i+1, input.source, input.wantResult, input.wantErr)
|
||||||
|
122
scanner.go
122
scanner.go
@ -219,6 +219,8 @@ func (self *scanner) fetchNextToken() (tk *Token) {
|
|||||||
case '<':
|
case '<':
|
||||||
if next, _ := self.peek(); next == '=' {
|
if next, _ := self.peek(); next == '=' {
|
||||||
tk = self.moveOn(SymLessOrEqual, ch, next)
|
tk = self.moveOn(SymLessOrEqual, ch, next)
|
||||||
|
} else if next == '<' {
|
||||||
|
tk = self.moveOn(SymAppend, ch, next)
|
||||||
} else if next == '>' {
|
} else if next == '>' {
|
||||||
tk = self.moveOn(SymLessGreater, ch, next)
|
tk = self.moveOn(SymLessGreater, ch, next)
|
||||||
} else {
|
} else {
|
||||||
@ -227,6 +229,8 @@ func (self *scanner) fetchNextToken() (tk *Token) {
|
|||||||
case '>':
|
case '>':
|
||||||
if next, _ := self.peek(); next == '=' {
|
if next, _ := self.peek(); next == '=' {
|
||||||
tk = self.moveOn(SymGreaterOrEqual, ch, next)
|
tk = self.moveOn(SymGreaterOrEqual, ch, next)
|
||||||
|
} else if next == '>' {
|
||||||
|
tk = self.moveOn(SymInsert, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = self.makeToken(SymGreater, ch)
|
tk = self.makeToken(SymGreater, ch)
|
||||||
}
|
}
|
||||||
@ -276,62 +280,116 @@ func (self *scanner) sync(err error) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isBinaryDigit(ch byte) bool {
|
||||||
|
return ch == '0' || ch == '1'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isOctalDigit(ch byte) bool {
|
||||||
|
return ch >= '0' && ch <= '7'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDecimalDigit(ch byte) bool {
|
||||||
|
return ch >= '0' && ch <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isHexDigit(ch byte) bool {
|
||||||
|
return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *scanner) initBase(sb *strings.Builder, currentFirstCh byte) (firstCh byte, numBase int, digitFunc func(byte) bool, err error) {
|
||||||
|
var ch byte
|
||||||
|
var digitType string
|
||||||
|
firstCh = currentFirstCh
|
||||||
|
digitFunc = isDecimalDigit
|
||||||
|
numBase = 10
|
||||||
|
|
||||||
|
if ch, err = self.peek(); err == nil {
|
||||||
|
if ch == 'b' || ch == 'B' {
|
||||||
|
numBase = 2
|
||||||
|
digitType = "binary"
|
||||||
|
self.readChar()
|
||||||
|
digitFunc = isBinaryDigit
|
||||||
|
firstCh, err = self.readChar()
|
||||||
|
} else if ch == 'o' || ch == 'O' {
|
||||||
|
numBase = 8
|
||||||
|
digitType = "octal"
|
||||||
|
self.readChar()
|
||||||
|
digitFunc = isOctalDigit
|
||||||
|
firstCh, err = self.readChar()
|
||||||
|
} else if ch == 'x' || ch == 'X' {
|
||||||
|
numBase = 16
|
||||||
|
digitType = "hex"
|
||||||
|
self.readChar()
|
||||||
|
digitFunc = isHexDigit
|
||||||
|
firstCh, err = self.readChar()
|
||||||
|
}
|
||||||
|
if err == nil && !digitFunc(firstCh) {
|
||||||
|
if len(digitType) == 0 {
|
||||||
|
digitType = "decimal"
|
||||||
|
}
|
||||||
|
err = fmt.Errorf("expected %s digit, got '%c'", digitType, firstCh)
|
||||||
|
}
|
||||||
|
} else if err == io.EOF {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (self *scanner) parseNumber(firstCh byte) (tk *Token) {
|
func (self *scanner) parseNumber(firstCh byte) (tk *Token) {
|
||||||
var err error
|
var err error
|
||||||
var ch byte
|
var ch byte
|
||||||
var sym Symbol = SymInteger
|
var sym Symbol = SymInteger
|
||||||
var value any
|
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
|
var isDigit func(byte) bool = isDecimalDigit
|
||||||
|
var numBase = 10
|
||||||
|
|
||||||
for ch = firstCh; err == nil && (ch >= '0' && ch <= '9'); ch, err = self.readChar() {
|
if firstCh == '0' {
|
||||||
|
firstCh, numBase, isDigit, err = self.initBase(&sb, firstCh)
|
||||||
|
}
|
||||||
|
for ch = firstCh; err == nil && isDigit(ch); ch, err = self.readChar() {
|
||||||
sb.WriteByte(ch)
|
sb.WriteByte(ch)
|
||||||
}
|
}
|
||||||
if ch == '.' {
|
|
||||||
sym = SymFloat
|
if numBase == 10 {
|
||||||
sb.WriteByte(ch)
|
if err == nil && ch == '.' {
|
||||||
ch, err = self.readChar()
|
sym = SymFloat
|
||||||
if ch >= '0' && ch <= '9' {
|
sb.WriteByte(ch)
|
||||||
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = self.readChar() {
|
ch, err = self.readChar()
|
||||||
sb.WriteByte(ch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ch == 'e' || ch == 'E' {
|
|
||||||
sym = SymFloat
|
|
||||||
sb.WriteByte(ch)
|
|
||||||
if ch, err = self.readChar(); err == nil {
|
|
||||||
if ch == '+' || ch == '-' {
|
|
||||||
sb.WriteByte(ch)
|
|
||||||
ch, err = self.readChar()
|
|
||||||
}
|
|
||||||
if ch >= '0' && ch <= '9' {
|
if ch >= '0' && ch <= '9' {
|
||||||
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = self.readChar() {
|
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = self.readChar() {
|
||||||
sb.WriteByte(ch)
|
sb.WriteByte(ch)
|
||||||
}
|
}
|
||||||
//err = self.sync(err)
|
|
||||||
} else {
|
|
||||||
err = errors.New("expected integer exponent")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// } else {
|
if err == nil && (ch == 'e' || ch == 'E') {
|
||||||
// err = self.sync(err)
|
sym = SymFloat
|
||||||
|
sb.WriteByte(ch)
|
||||||
|
if ch, err = self.readChar(); err == nil {
|
||||||
|
if ch == '+' || ch == '-' {
|
||||||
|
sb.WriteByte(ch)
|
||||||
|
ch, err = self.readChar()
|
||||||
|
}
|
||||||
|
if ch >= '0' && ch <= '9' {
|
||||||
|
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = self.readChar() {
|
||||||
|
sb.WriteByte(ch)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = errors.New("expected integer exponent")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
tk = self.makeErrorToken(err)
|
tk = self.makeErrorToken(err)
|
||||||
} else {
|
} else {
|
||||||
|
var value any
|
||||||
err = self.sync(err)
|
err = self.sync(err)
|
||||||
txt := sb.String()
|
txt := sb.String()
|
||||||
if sym == SymFloat {
|
if sym == SymFloat {
|
||||||
value, err = strconv.ParseFloat(txt, 64)
|
value, err = strconv.ParseFloat(txt, 64)
|
||||||
} else if strings.HasPrefix(txt, "0x") {
|
|
||||||
value, err = strconv.ParseInt(txt, 16, 64)
|
|
||||||
} else if strings.HasPrefix(txt, "0o") {
|
|
||||||
value, err = strconv.ParseInt(txt, 8, 64)
|
|
||||||
} else if strings.HasPrefix(txt, "0b") {
|
|
||||||
value, err = strconv.ParseInt(txt, 2, 64)
|
|
||||||
} else {
|
} else {
|
||||||
value, err = strconv.ParseInt(txt, 10, 64)
|
value, err = strconv.ParseInt(txt, numBase, 64)
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tk = self.makeValueToken(sym, txt, value)
|
tk = self.makeValueToken(sym, txt, value)
|
||||||
|
@ -59,6 +59,8 @@ const (
|
|||||||
SymQuestionEqual // 48: '?='
|
SymQuestionEqual // 48: '?='
|
||||||
SymDoubleAt // 49: '@@'
|
SymDoubleAt // 49: '@@'
|
||||||
SymDoubleColon // 50: '::'
|
SymDoubleColon // 50: '::'
|
||||||
|
SymInsert // 51: '>>'
|
||||||
|
SymAppend // 52: '<<'
|
||||||
SymChangeSign
|
SymChangeSign
|
||||||
SymUnchangeSign
|
SymUnchangeSign
|
||||||
SymIdentifier
|
SymIdentifier
|
||||||
|
14
token.go
14
token.go
@ -67,3 +67,17 @@ func (self *Token) Errorf(template string, args ...any) (err error) {
|
|||||||
err = fmt.Errorf(fmt.Sprintf("[%d:%d] ", self.row, self.col)+template, args...)
|
err = fmt.Errorf(fmt.Sprintf("[%d:%d] ", self.row, self.col)+template, args...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Token) Error() (err error) {
|
||||||
|
if self.Sym == SymError {
|
||||||
|
if msg, ok := self.Value.(error); ok {
|
||||||
|
err = fmt.Errorf("[%d:%d] %v", self.row, self.col, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Token) Errors(msg string) (err error) {
|
||||||
|
err = fmt.Errorf("[%d:%d] %v", self.row, self.col, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user