mirror of https://github.com/anoshenko/rui.git
Changed ParseDataText function return values
This commit is contained in:
parent
3090a0e94f
commit
c3c8b9e858
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
* Added support of binding
|
* Added support of binding
|
||||||
* Added "binding" argument to CreateViewFromResources, CreateViewFromText, and CreateViewFromObject functions
|
* Added "binding" argument to CreateViewFromResources, CreateViewFromText, and CreateViewFromObject functions
|
||||||
|
* Changed ParseDataText function return values
|
||||||
|
|
||||||
# v0.19.0
|
# v0.19.0
|
||||||
|
|
||||||
|
|
19
appServer.go
19
appServer.go
|
@ -164,7 +164,12 @@ func (app *application) postHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
DebugLog(message)
|
DebugLog(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj := ParseDataText(message); obj != nil {
|
obj, err := ParseDataText(message)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var session Session = nil
|
var session Session = nil
|
||||||
var response chan string = nil
|
var response chan string = nil
|
||||||
|
|
||||||
|
@ -224,7 +229,6 @@ func (app *application) postHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (app *application) socketReader(bridge *wsBridge) {
|
func (app *application) socketReader(bridge *wsBridge) {
|
||||||
var session Session
|
var session Session
|
||||||
|
@ -241,9 +245,13 @@ func (app *application) socketReader(bridge *wsBridge) {
|
||||||
DebugLog("🖥️ -> " + message)
|
DebugLog("🖥️ -> " + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj := ParseDataText(message); obj != nil {
|
obj, err := ParseDataText(message)
|
||||||
command := obj.Tag()
|
if err != nil {
|
||||||
switch command {
|
ErrorLog(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch command := obj.Tag(); command {
|
||||||
case "startSession":
|
case "startSession":
|
||||||
answer := ""
|
answer := ""
|
||||||
if session, answer = app.startSession(obj, events, bridge, nil); session != nil {
|
if session, answer = app.startSession(obj, events, bridge, nil); session != nil {
|
||||||
|
@ -296,7 +304,6 @@ func (app *application) socketReader(bridge *wsBridge) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func sessionEventHandler(session Session, events chan DataObject, bridge bridge) {
|
func sessionEventHandler(session Session, events chan DataObject, bridge bridge) {
|
||||||
for {
|
for {
|
||||||
|
|
|
@ -78,6 +78,16 @@ func createBackground(obj DataObject) BackgroundElement {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseBackgroundText(text string) BackgroundElement {
|
||||||
|
obj, err := ParseDataText(text)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return createBackground(obj)
|
||||||
|
}
|
||||||
|
|
||||||
func parseBackgroundValue(value any) []BackgroundElement {
|
func parseBackgroundValue(value any) []BackgroundElement {
|
||||||
|
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
|
@ -96,15 +106,11 @@ func parseBackgroundValue(value any) []BackgroundElement {
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else if obj := ParseDataText(el.Value()); obj != nil {
|
} else if element := parseBackgroundText(el.Value()); element != nil {
|
||||||
if element := createBackground(obj); element != nil {
|
|
||||||
background = append(background, element)
|
background = append(background, element)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return background
|
return background
|
||||||
|
|
||||||
|
@ -125,44 +131,34 @@ func parseBackgroundValue(value any) []BackgroundElement {
|
||||||
return background
|
return background
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if obj := ParseDataText(value); obj != nil {
|
if element := parseBackgroundText(value); element != nil {
|
||||||
if element := createBackground(obj); element != nil {
|
|
||||||
return []BackgroundElement{element}
|
return []BackgroundElement{element}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
case []string:
|
case []string:
|
||||||
elements := make([]BackgroundElement, 0, len(value))
|
elements := make([]BackgroundElement, 0, len(value))
|
||||||
for _, element := range value {
|
for _, text := range value {
|
||||||
if obj := ParseDataText(element); obj != nil {
|
if element := parseBackgroundText(text); element != nil {
|
||||||
if element := createBackground(obj); element != nil {
|
|
||||||
elements = append(elements, element)
|
elements = append(elements, element)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return elements
|
return elements
|
||||||
|
|
||||||
case []any:
|
case []any:
|
||||||
elements := make([]BackgroundElement, 0, len(value))
|
elements := make([]BackgroundElement, 0, len(value))
|
||||||
for _, element := range value {
|
for _, val := range value {
|
||||||
switch element := element.(type) {
|
switch val := val.(type) {
|
||||||
case BackgroundElement:
|
case BackgroundElement:
|
||||||
elements = append(elements, element)
|
elements = append(elements, val)
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if obj := ParseDataText(element); obj != nil {
|
if element := parseBackgroundText(val); element != nil {
|
||||||
if element := createBackground(obj); element != nil {
|
|
||||||
elements = append(elements, element)
|
elements = append(elements, element)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -610,7 +610,10 @@ func borderSet(properties Properties, tag PropertyName, value any) []PropertyNam
|
||||||
case Left, Right, Top, Bottom:
|
case Left, Right, Top, Bottom:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
if obj := ParseDataText(value); obj != nil {
|
obj, err := ParseDataText(value)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else {
|
||||||
return setSingleBorderObject(tag, obj)
|
return setSingleBorderObject(tag, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
383
data.go
383
data.go
|
@ -1,6 +1,8 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
@ -48,6 +50,9 @@ type DataObject interface {
|
||||||
|
|
||||||
// ToParams create a params(map) representation of a data object
|
// ToParams create a params(map) representation of a data object
|
||||||
ToParams() Params
|
ToParams() Params
|
||||||
|
|
||||||
|
// PropertyByTag removes a data node corresponding to a property tag and returns it
|
||||||
|
RemovePropertyByTag(tag string) DataNode
|
||||||
}
|
}
|
||||||
|
|
||||||
// DataNodeType defines the type of DataNode
|
// DataNodeType defines the type of DataNode
|
||||||
|
@ -162,6 +167,28 @@ func (object *dataObject) PropertyByTag(tag string) DataNode {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (object *dataObject) RemovePropertyByTag(tag string) DataNode {
|
||||||
|
if object.property != nil {
|
||||||
|
for i, node := range object.property {
|
||||||
|
if node.Tag() == tag {
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
object.property = object.property[1:]
|
||||||
|
|
||||||
|
case len(object.property) - 1:
|
||||||
|
object.property = object.property[:len(object.property)-1]
|
||||||
|
|
||||||
|
default:
|
||||||
|
object.property = append(object.property[:i], object.property[i+1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (object *dataObject) PropertyValue(tag string) (string, bool) {
|
func (object *dataObject) PropertyValue(tag string) (string, bool) {
|
||||||
if node := object.PropertyByTag(tag); node != nil && node.Type() == TextNode {
|
if node := object.PropertyByTag(tag); node != nil && node.Type() == TextNode {
|
||||||
return node.Text(), true
|
return node.Text(), true
|
||||||
|
@ -318,54 +345,49 @@ func (node *dataNode) ArrayAsParams() []Params {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseDataText - parse text and return DataNode
|
type dataParser struct {
|
||||||
func ParseDataText(text string) DataObject {
|
data []rune
|
||||||
|
size int
|
||||||
if strings.ContainsAny(text, "\r") {
|
pos int
|
||||||
text = strings.ReplaceAll(text, "\r\n", "\n")
|
line int
|
||||||
text = strings.ReplaceAll(text, "\r", "\n")
|
lineStart int
|
||||||
}
|
}
|
||||||
data := append([]rune(text), rune(0))
|
|
||||||
pos := 0
|
|
||||||
size := len(data) - 1
|
|
||||||
line := 1
|
|
||||||
lineStart := 0
|
|
||||||
|
|
||||||
skipSpaces := func(skipNewLine bool) {
|
func (parser *dataParser) skipSpaces(skipNewLine bool) {
|
||||||
for pos < size {
|
for parser.pos < parser.size {
|
||||||
switch data[pos] {
|
switch parser.data[parser.pos] {
|
||||||
case '\n':
|
case '\n':
|
||||||
if !skipNewLine {
|
if !skipNewLine {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
line++
|
parser.line++
|
||||||
lineStart = pos + 1
|
parser.lineStart = parser.pos + 1
|
||||||
|
|
||||||
case '/':
|
case '/':
|
||||||
if pos+1 < size {
|
if parser.pos+1 < parser.size {
|
||||||
switch data[pos+1] {
|
switch parser.data[parser.pos+1] {
|
||||||
case '/':
|
case '/':
|
||||||
pos += 2
|
parser.pos += 2
|
||||||
for pos < size && data[pos] != '\n' {
|
for parser.pos < parser.size && parser.data[parser.pos] != '\n' {
|
||||||
pos++
|
parser.pos++
|
||||||
}
|
}
|
||||||
pos--
|
parser.pos--
|
||||||
|
|
||||||
case '*':
|
case '*':
|
||||||
pos += 3
|
parser.pos += 3
|
||||||
for {
|
for {
|
||||||
if pos >= size {
|
if parser.pos >= parser.size {
|
||||||
ErrorLog("Unexpected end of file")
|
ErrorLog("Unexpected end of file")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if data[pos-1] == '*' && data[pos] == '/' {
|
if parser.data[parser.pos-1] == '*' && parser.data[parser.pos] == '/' {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if data[pos-1] == '\n' {
|
if parser.data[parser.pos-1] == '\n' {
|
||||||
line++
|
parser.line++
|
||||||
lineStart = pos
|
parser.lineStart = parser.pos
|
||||||
}
|
}
|
||||||
pos++
|
parser.pos++
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -377,75 +399,72 @@ func ParseDataText(text string) DataObject {
|
||||||
// do nothing
|
// do nothing
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if !unicode.IsSpace(data[pos]) {
|
if !unicode.IsSpace(parser.data[parser.pos]) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pos++
|
parser.pos++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parseTag := func() (string, bool) {
|
func (parser *dataParser) parseTag() (string, error) {
|
||||||
skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
startPos := pos
|
startPos := parser.pos
|
||||||
switch data[pos] {
|
switch parser.data[parser.pos] {
|
||||||
case '`':
|
case '`':
|
||||||
pos++
|
parser.pos++
|
||||||
startPos++
|
startPos++
|
||||||
for data[pos] != '`' {
|
for parser.data[parser.pos] != '`' {
|
||||||
pos++
|
parser.pos++
|
||||||
if pos >= size {
|
if parser.pos >= parser.size {
|
||||||
ErrorLog("Unexpected end of text")
|
return string(parser.data[startPos:parser.size]), errors.New("unexpected end of text")
|
||||||
return string(data[startPos:size]), false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
str := string(data[startPos:pos])
|
str := string(parser.data[startPos:parser.pos])
|
||||||
pos++
|
parser.pos++
|
||||||
return str, true
|
return str, nil
|
||||||
|
|
||||||
case '\'', '"':
|
case '\'', '"':
|
||||||
stopSymbol := data[pos]
|
stopSymbol := parser.data[parser.pos]
|
||||||
pos++
|
parser.pos++
|
||||||
startPos++
|
startPos++
|
||||||
slash := false
|
slash := false
|
||||||
for stopSymbol != data[pos] {
|
for stopSymbol != parser.data[parser.pos] {
|
||||||
if data[pos] == '\\' {
|
if parser.data[parser.pos] == '\\' {
|
||||||
pos += 2
|
parser.pos += 2
|
||||||
slash = true
|
slash = true
|
||||||
} else {
|
} else {
|
||||||
pos++
|
parser.pos++
|
||||||
}
|
}
|
||||||
if pos >= size {
|
if parser.pos >= parser.size {
|
||||||
ErrorLog("Unexpected end of text")
|
return string(parser.data[startPos:parser.size]), errors.New("unexpected end of text")
|
||||||
return string(data[startPos:size]), false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !slash {
|
if !slash {
|
||||||
str := string(data[startPos:pos])
|
str := string(parser.data[startPos:parser.pos])
|
||||||
pos++
|
parser.pos++
|
||||||
skipSpaces(false)
|
parser.skipSpaces(false)
|
||||||
return str, true
|
return str, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer := make([]rune, pos-startPos+1)
|
buffer := make([]rune, parser.pos-startPos+1)
|
||||||
n1 := 0
|
n1 := 0
|
||||||
n2 := startPos
|
n2 := startPos
|
||||||
|
|
||||||
invalidEscape := func() (string, bool) {
|
invalidEscape := func() (string, error) {
|
||||||
str := string(data[startPos:pos])
|
str := string(parser.data[startPos:parser.pos])
|
||||||
pos++
|
parser.pos++
|
||||||
ErrorLogF("Invalid escape sequence in \"%s\" (position %d)", str, n2-2-startPos)
|
return str, fmt.Errorf(`invalid escape sequence in "%s" (position %d)`, str, n2-2-startPos)
|
||||||
return str, false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for n2 < pos {
|
for n2 < parser.pos {
|
||||||
if data[n2] != '\\' {
|
if parser.data[n2] != '\\' {
|
||||||
buffer[n1] = data[n2]
|
buffer[n1] = parser.data[n2]
|
||||||
n2++
|
n2++
|
||||||
} else {
|
} else {
|
||||||
n2 += 2
|
n2 += 2
|
||||||
switch data[n2-1] {
|
switch parser.data[n2-1] {
|
||||||
case 'n':
|
case 'n':
|
||||||
buffer[n1] = '\n'
|
buffer[n1] = '\n'
|
||||||
|
|
||||||
|
@ -465,12 +484,12 @@ func ParseDataText(text string) DataObject {
|
||||||
buffer[n1] = '\\'
|
buffer[n1] = '\\'
|
||||||
|
|
||||||
case 'x', 'X':
|
case 'x', 'X':
|
||||||
if n2+2 > pos {
|
if n2+2 > parser.pos {
|
||||||
return invalidEscape()
|
return invalidEscape()
|
||||||
}
|
}
|
||||||
x := 0
|
x := 0
|
||||||
for range 2 {
|
for range 2 {
|
||||||
ch := data[n2]
|
ch := parser.data[n2]
|
||||||
if ch >= '0' && ch <= '9' {
|
if ch >= '0' && ch <= '9' {
|
||||||
x = x*16 + int(ch-'0')
|
x = x*16 + int(ch-'0')
|
||||||
} else if ch >= 'a' && ch <= 'f' {
|
} else if ch >= 'a' && ch <= 'f' {
|
||||||
|
@ -485,12 +504,12 @@ func ParseDataText(text string) DataObject {
|
||||||
buffer[n1] = rune(x)
|
buffer[n1] = rune(x)
|
||||||
|
|
||||||
case 'u', 'U':
|
case 'u', 'U':
|
||||||
if n2+4 > pos {
|
if n2+4 > parser.pos {
|
||||||
return invalidEscape()
|
return invalidEscape()
|
||||||
}
|
}
|
||||||
x := 0
|
x := 0
|
||||||
for range 4 {
|
for range 4 {
|
||||||
ch := data[n2]
|
ch := parser.data[n2]
|
||||||
if ch >= '0' && ch <= '9' {
|
if ch >= '0' && ch <= '9' {
|
||||||
x = x*16 + int(ch-'0')
|
x = x*16 + int(ch-'0')
|
||||||
} else if ch >= 'a' && ch <= 'f' {
|
} else if ch >= 'a' && ch <= 'f' {
|
||||||
|
@ -505,90 +524,84 @@ func ParseDataText(text string) DataObject {
|
||||||
buffer[n1] = rune(x)
|
buffer[n1] = rune(x)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
str := string(data[startPos:pos])
|
str := string(parser.data[startPos:parser.pos])
|
||||||
ErrorLogF("Invalid escape sequence in \"%s\" (position %d)", str, n2-2-startPos)
|
return str, fmt.Errorf(`invalid escape sequence in "%s" (position %d)`, str, n2-2-startPos)
|
||||||
return str, false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n1++
|
n1++
|
||||||
}
|
}
|
||||||
|
|
||||||
pos++
|
parser.pos++
|
||||||
skipSpaces(false)
|
parser.skipSpaces(false)
|
||||||
return string(buffer[0:n1]), true
|
return string(buffer[0:n1]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
stopSymbol := func(symbol rune) bool {
|
for parser.pos < parser.size && !parser.stopSymbol(parser.data[parser.pos]) {
|
||||||
|
parser.pos++
|
||||||
|
}
|
||||||
|
|
||||||
|
endPos := parser.pos
|
||||||
|
parser.skipSpaces(false)
|
||||||
|
if startPos == endPos {
|
||||||
|
//ErrorLog("empty tag")
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return string(parser.data[startPos:endPos]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (parser *dataParser) stopSymbol(symbol rune) bool {
|
||||||
return unicode.IsSpace(symbol) ||
|
return unicode.IsSpace(symbol) ||
|
||||||
slices.Contains([]rune{'=', '{', '}', '[', ']', ',', ' ', '\t', '\n', '\'', '"', '`', '/'}, symbol)
|
slices.Contains([]rune{'=', '{', '}', '[', ']', ',', ' ', '\t', '\n', '\'', '"', '`', '/'}, symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
for pos < size && !stopSymbol(data[pos]) {
|
func (parser *dataParser) parseNode() (DataNode, error) {
|
||||||
pos++
|
|
||||||
}
|
|
||||||
|
|
||||||
endPos := pos
|
|
||||||
skipSpaces(false)
|
|
||||||
if startPos == endPos {
|
|
||||||
//ErrorLog("empty tag")
|
|
||||||
return "", true
|
|
||||||
}
|
|
||||||
return string(data[startPos:endPos]), true
|
|
||||||
}
|
|
||||||
|
|
||||||
var parseObject func(tag string) DataObject
|
|
||||||
var parseArray func() []DataValue
|
|
||||||
|
|
||||||
parseNode := func() DataNode {
|
|
||||||
var tag string
|
var tag string
|
||||||
var ok bool
|
var err error
|
||||||
|
|
||||||
if tag, ok = parseTag(); !ok {
|
if tag, err = parser.parseTag(); err != nil {
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
if data[pos] != '=' {
|
if parser.data[parser.pos] != '=' {
|
||||||
ErrorLogF("expected '=' after a tag name (line: %d, position: %d)", line, pos-lineStart)
|
return nil, fmt.Errorf("expected '=' after a tag name (line: %d, position: %d)", parser.line, parser.pos-parser.lineStart)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pos++
|
parser.pos++
|
||||||
skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
switch data[pos] {
|
switch parser.data[parser.pos] {
|
||||||
case '[':
|
case '[':
|
||||||
node := new(dataNode)
|
node := new(dataNode)
|
||||||
node.tag = tag
|
node.tag = tag
|
||||||
|
|
||||||
if node.array = parseArray(); node.array == nil {
|
if node.array, err = parser.parseArray(); err != nil {
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
return node
|
return node, nil
|
||||||
|
|
||||||
case '{':
|
case '{':
|
||||||
node := new(dataNode)
|
node := new(dataNode)
|
||||||
node.tag = tag
|
node.tag = tag
|
||||||
if node.value = parseObject("_"); node.value == nil {
|
if node.value, err = parser.parseObject("_"); err != nil {
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
return node
|
return node, nil
|
||||||
|
|
||||||
case '}', ']', '=':
|
case '}', ']', '=':
|
||||||
ErrorLogF("Expected '[', '{' or a tag name after '=' (line: %d, position: %d)", line, pos-lineStart)
|
return nil, fmt.Errorf(`expected '[', '{' or a tag name after '=' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
||||||
return nil
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var str string
|
var str string
|
||||||
if str, ok = parseTag(); !ok {
|
if str, err = parser.parseTag(); err != nil {
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
node := new(dataNode)
|
node := new(dataNode)
|
||||||
node.tag = tag
|
node.tag = tag
|
||||||
|
|
||||||
if data[pos] == '{' {
|
if parser.data[parser.pos] == '{' {
|
||||||
if node.value = parseObject(str); node.value == nil {
|
if node.value, err = parser.parseObject(str); err != nil {
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val := new(dataStringValue)
|
val := new(dataStringValue)
|
||||||
|
@ -596,91 +609,88 @@ func ParseDataText(text string) DataObject {
|
||||||
node.value = val
|
node.value = val
|
||||||
}
|
}
|
||||||
|
|
||||||
return node
|
return node, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parseObject = func(tag string) DataObject {
|
func (parser *dataParser) parseObject(tag string) (DataObject, error) {
|
||||||
if data[pos] != '{' {
|
if parser.data[parser.pos] != '{' {
|
||||||
ErrorLogF("Expected '{' (line: %d, position: %d)", line, pos-lineStart)
|
return nil, fmt.Errorf(`expected '{' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
pos++
|
parser.pos++
|
||||||
|
|
||||||
obj := new(dataObject)
|
obj := new(dataObject)
|
||||||
obj.tag = tag
|
obj.tag = tag
|
||||||
obj.property = []DataNode{}
|
obj.property = []DataNode{}
|
||||||
|
|
||||||
for pos < size {
|
for parser.pos < parser.size {
|
||||||
var node DataNode
|
parser.skipSpaces(true)
|
||||||
|
if parser.data[parser.pos] == '}' {
|
||||||
skipSpaces(true)
|
parser.pos++
|
||||||
if data[pos] == '}' {
|
parser.skipSpaces(false)
|
||||||
pos++
|
return obj, nil
|
||||||
skipSpaces(false)
|
|
||||||
return obj
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if node = parseNode(); node == nil {
|
node, err := parser.parseNode()
|
||||||
return nil
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.property = append(obj.property, node)
|
obj.property = append(obj.property, node)
|
||||||
if data[pos] == '}' {
|
if parser.data[parser.pos] == '}' {
|
||||||
pos++
|
parser.pos++
|
||||||
skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
return obj
|
return obj, nil
|
||||||
} else if data[pos] != ',' && data[pos] != '\n' {
|
} else if parser.data[parser.pos] != ',' && parser.data[parser.pos] != '\n' {
|
||||||
ErrorLogF(`Expected '}', '\n' or ',' (line: %d, position: %d)`, line, pos-lineStart)
|
return nil, fmt.Errorf(`expected '}', '\n' or ',' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
if data[pos] != '\n' {
|
|
||||||
pos++
|
if parser.data[parser.pos] != '\n' {
|
||||||
|
parser.pos++
|
||||||
}
|
}
|
||||||
skipSpaces(true)
|
|
||||||
for data[pos] == ',' {
|
parser.skipSpaces(true)
|
||||||
pos++
|
for parser.data[parser.pos] == ',' {
|
||||||
skipSpaces(true)
|
parser.pos++
|
||||||
|
parser.skipSpaces(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLog("Unexpected end of text")
|
return nil, errors.New("unexpected end of text")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parseArray = func() []DataValue {
|
func (parser *dataParser) parseArray() ([]DataValue, error) {
|
||||||
pos++
|
parser.pos++
|
||||||
skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
|
|
||||||
array := []DataValue{}
|
array := []DataValue{}
|
||||||
|
|
||||||
for pos < size {
|
for parser.pos < parser.size {
|
||||||
var tag string
|
parser.skipSpaces(true)
|
||||||
var ok bool
|
for parser.data[parser.pos] == ',' && parser.pos < parser.size {
|
||||||
|
parser.pos++
|
||||||
skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
for data[pos] == ',' && pos < size {
|
|
||||||
pos++
|
|
||||||
skipSpaces(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if pos >= size {
|
if parser.pos >= parser.size {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if data[pos] == ']' {
|
if parser.data[parser.pos] == ']' {
|
||||||
pos++
|
parser.pos++
|
||||||
skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
return array
|
return array, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if tag, ok = parseTag(); !ok {
|
tag, err := parser.parseTag()
|
||||||
return nil
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if data[pos] == '{' {
|
if parser.data[parser.pos] == '{' {
|
||||||
obj := parseObject(tag)
|
obj, err := parser.parseObject(tag)
|
||||||
if obj == nil {
|
if err != nil {
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
array = append(array, obj)
|
array = append(array, obj)
|
||||||
} else {
|
} else {
|
||||||
|
@ -689,12 +699,11 @@ func ParseDataText(text string) DataObject {
|
||||||
array = append(array, val)
|
array = append(array, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch data[pos] {
|
switch parser.data[parser.pos] {
|
||||||
case ']', ',', '\n':
|
case ']', ',', '\n':
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ErrorLogF("Expected ']' or ',' (line: %d, position: %d)", line, pos-lineStart)
|
return nil, fmt.Errorf(`expected ']' or ',' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -710,12 +719,28 @@ func ParseDataText(text string) DataObject {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLog("Unexpected end of text")
|
return nil, errors.New("unexpected end of text")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if tag, ok := parseTag(); ok {
|
// ParseDataText - parse text and return DataNode
|
||||||
return parseObject(tag)
|
func ParseDataText(text string) (DataObject, error) {
|
||||||
|
|
||||||
|
if strings.ContainsAny(text, "\r") {
|
||||||
|
text = strings.ReplaceAll(text, "\r\n", "\n")
|
||||||
|
text = strings.ReplaceAll(text, "\r", "\n")
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
parser := dataParser{
|
||||||
|
data: append([]rune(text), rune(0)),
|
||||||
|
pos: 0,
|
||||||
|
line: 1,
|
||||||
|
lineStart: 0,
|
||||||
|
}
|
||||||
|
parser.size = len(parser.data) - 1
|
||||||
|
|
||||||
|
tag, err := parser.parseTag()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return parser.parseObject(tag)
|
||||||
}
|
}
|
||||||
|
|
15
data_test.go
15
data_test.go
|
@ -6,10 +6,6 @@ import (
|
||||||
|
|
||||||
func TestParseDataText(t *testing.T) {
|
func TestParseDataText(t *testing.T) {
|
||||||
|
|
||||||
SetErrorLog(func(text string) {
|
|
||||||
t.Error(text)
|
|
||||||
})
|
|
||||||
|
|
||||||
text := `obj1 {
|
text := `obj1 {
|
||||||
key1 = val1,
|
key1 = val1,
|
||||||
key2=obj2{
|
key2=obj2{
|
||||||
|
@ -27,8 +23,10 @@ func TestParseDataText(t *testing.T) {
|
||||||
key3 = "\n \t \\ \r \" ' \X4F\x4e \U01Ea",` +
|
key3 = "\n \t \\ \r \" ' \X4F\x4e \U01Ea",` +
|
||||||
"key4=`" + `\n \t \\ \r \" ' \x8F \UF80a` + "`\r}"
|
"key4=`" + `\n \t \\ \r \" ' \x8F \UF80a` + "`\r}"
|
||||||
|
|
||||||
obj := ParseDataText(text)
|
obj, err := ParseDataText(text)
|
||||||
if obj != nil {
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else {
|
||||||
if obj.Tag() != "obj1" {
|
if obj.Tag() != "obj1" {
|
||||||
t.Error(`obj.Tag() != "obj1"`)
|
t.Error(`obj.Tag() != "obj1"`)
|
||||||
}
|
}
|
||||||
|
@ -173,9 +171,6 @@ func TestParseDataText(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetErrorLog(func(text string) {
|
|
||||||
})
|
|
||||||
|
|
||||||
failText := []string{
|
failText := []string{
|
||||||
" ",
|
" ",
|
||||||
"obj[]",
|
"obj[]",
|
||||||
|
@ -204,7 +199,7 @@ func TestParseDataText(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, txt := range failText {
|
for _, txt := range failText {
|
||||||
if obj := ParseDataText(txt); obj != nil {
|
if _, err := ParseDataText(txt); err == nil {
|
||||||
t.Errorf("result ParseDataText(\"%s\") must be fail", txt)
|
t.Errorf("result ParseDataText(\"%s\") must be fail", txt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
popup.go
19
popup.go
|
@ -941,6 +941,25 @@ func NewPopup(view View, param Params) Popup {
|
||||||
return popup
|
return popup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func CreatePopupFromObject(session Session, object DataObject, binding any) Popup {
|
||||||
|
node := object.RemovePropertyByTag(string(Content))
|
||||||
|
if node == nil {
|
||||||
|
ErrorLog(`"content" property not found`)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch node.Type() {
|
||||||
|
case ObjectNode:
|
||||||
|
|
||||||
|
case TextNode:
|
||||||
|
|
||||||
|
default:
|
||||||
|
ErrorLog(`Unsupported data of "content" property`)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
// ShowPopup creates a new Popup and shows it
|
// ShowPopup creates a new Popup and shows it
|
||||||
func ShowPopup(view View, param Params) Popup {
|
func ShowPopup(view View, param Params) Popup {
|
||||||
popup := NewPopup(view, param)
|
popup := NewPopup(view, param)
|
||||||
|
|
|
@ -266,7 +266,8 @@ func (session *sessionData) setBridge(events chan DataObject, bridge bridge) {
|
||||||
|
|
||||||
func (session *sessionData) close() {
|
func (session *sessionData) close() {
|
||||||
if session.events != nil {
|
if session.events != nil {
|
||||||
session.events <- ParseDataText(`session-close{session="` + strconv.Itoa(session.sessionID) + `"}`)
|
obj, _ := ParseDataText(`session-close{session="` + strconv.Itoa(session.sessionID) + `"}`)
|
||||||
|
session.events <- obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,8 +50,9 @@ func (resources *resourceManager) scanStringsDir(path string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadStringResources(text string) {
|
func loadStringResources(text string) {
|
||||||
data := ParseDataText(text)
|
data, err := ParseDataText(text)
|
||||||
if data == nil {
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
theme.go
7
theme.go
|
@ -686,8 +686,11 @@ func (theme *theme) addText(themeText string) bool {
|
||||||
theme.init()
|
theme.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
data := ParseDataText(themeText)
|
data, err := ParseDataText(themeText)
|
||||||
if data == nil || !data.IsObject() || data.Tag() != "theme" {
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return false
|
||||||
|
} else if !data.IsObject() || data.Tag() != "theme" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -398,7 +398,10 @@ func valueToTransformProperty(value any) TransformProperty {
|
||||||
}
|
}
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if obj := ParseDataText(value); obj != nil {
|
obj, err := ParseDataText(value)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else {
|
||||||
return parseObject(obj)
|
return parseObject(obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,15 +117,18 @@ func CreateViewFromObject(session Session, object DataObject, binding any) View
|
||||||
//
|
//
|
||||||
// If the function fails, it returns nil and an error message is written to the log.
|
// If the function fails, it returns nil and an error message is written to the log.
|
||||||
func CreateViewFromText(session Session, text string, binding ...any) View {
|
func CreateViewFromText(session Session, text string, binding ...any) View {
|
||||||
if data := ParseDataText(text); data != nil {
|
data, err := ParseDataText(text)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var b any = nil
|
var b any = nil
|
||||||
if len(binding) > 0 {
|
if len(binding) > 0 {
|
||||||
b = binding[0]
|
b = binding[0]
|
||||||
}
|
}
|
||||||
return CreateViewFromObject(session, data, b)
|
return CreateViewFromObject(session, data, b)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateViewFromResources create new View and initialize it by the content of
|
// CreateViewFromResources create new View and initialize it by the content of
|
||||||
// the resource file from "views" directory. Parameters:
|
// the resource file from "views" directory. Parameters:
|
||||||
|
@ -153,14 +156,20 @@ func CreateViewFromResources(session Session, name string, binding ...any) View
|
||||||
|
|
||||||
case viewDir:
|
case viewDir:
|
||||||
if data, err := fs.ReadFile(dir + "/" + name); err == nil {
|
if data, err := fs.ReadFile(dir + "/" + name); err == nil {
|
||||||
if data := ParseDataText(string(data)); data != nil {
|
data, err := ParseDataText(string(data))
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else {
|
||||||
return CreateViewFromObject(session, data, b)
|
return CreateViewFromObject(session, data, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if data, err := fs.ReadFile(dir + "/" + viewDir + "/" + name); err == nil {
|
if data, err := fs.ReadFile(dir + "/" + viewDir + "/" + name); err == nil {
|
||||||
if data := ParseDataText(string(data)); data != nil {
|
data, err := ParseDataText(string(data))
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else {
|
||||||
return CreateViewFromObject(session, data, b)
|
return CreateViewFromObject(session, data, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,7 +179,10 @@ func CreateViewFromResources(session Session, name string, binding ...any) View
|
||||||
|
|
||||||
if resources.path != "" {
|
if resources.path != "" {
|
||||||
if data, err := os.ReadFile(resources.path + viewDir + "/" + name); err == nil {
|
if data, err := os.ReadFile(resources.path + viewDir + "/" + name); err == nil {
|
||||||
if data := ParseDataText(string(data)); data != nil {
|
data, err := ParseDataText(string(data))
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else {
|
||||||
return CreateViewFromObject(session, data, b)
|
return CreateViewFromObject(session, data, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,13 +173,11 @@ func (container *viewsContainerData) htmlSubviews(self View, buffer *strings.Bui
|
||||||
}
|
}
|
||||||
|
|
||||||
func viewFromTextValue(text string, session Session) View {
|
func viewFromTextValue(text string, session Session) View {
|
||||||
if strings.Contains(text, "{") && strings.Contains(text, "}") {
|
if data, err := ParseDataText(text); err == nil {
|
||||||
if data := ParseDataText(text); data != nil {
|
|
||||||
if view := CreateViewFromObject(session, data, nil); view != nil {
|
if view := CreateViewFromObject(session, data, nil); view != nil {
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return NewTextView(session, Params{Text: text})
|
return NewTextView(session, Params{Text: text})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue