expressions now support intger value in bin (0b), oct (0o), and hex (0x) form

This commit is contained in:
Celestino Amoroso 2024-04-17 14:15:50 +02:00
parent b6887af77a
commit 54bc759f70
3 changed files with 105 additions and 33 deletions

View File

@ -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) {
var selectorTerm *term = nil
var currentTerm *term = nil
var tk *Token
tree = NewAst()
firstToken := true
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 {
continue
}
@ -281,6 +282,9 @@ func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef
}
lastSym = tk.Sym
}
if err == nil {
err = tk.Error()
}
return
}

View File

@ -280,17 +280,78 @@ func (self *scanner) sync(err error) error {
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) {
var err error
var ch byte
var sym Symbol = SymInteger
var value any
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)
}
if ch == '.' {
if numBase == 10 {
if err == nil && ch == '.' {
sym = SymFloat
sb.WriteByte(ch)
ch, err = self.readChar()
@ -300,7 +361,7 @@ func (self *scanner) parseNumber(firstCh byte) (tk *Token) {
}
}
}
if ch == 'e' || ch == 'E' {
if err == nil && (ch == 'e' || ch == 'E') {
sym = SymFloat
sb.WriteByte(ch)
if ch, err = self.readChar(); err == nil {
@ -312,30 +373,23 @@ func (self *scanner) parseNumber(firstCh byte) (tk *Token) {
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = self.readChar() {
sb.WriteByte(ch)
}
//err = self.sync(err)
} else {
err = errors.New("expected integer exponent")
}
}
// } else {
// err = self.sync(err)
}
}
if err != nil && err != io.EOF {
tk = self.makeErrorToken(err)
} else {
var value any
err = self.sync(err)
txt := sb.String()
if sym == SymFloat {
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 {
value, err = strconv.ParseInt(txt, 10, 64)
value, err = strconv.ParseInt(txt, numBase, 64)
}
if err == nil {
tk = self.makeValueToken(sym, txt, value)

View File

@ -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...)
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
}