-
Notifications
You must be signed in to change notification settings - Fork 0
/
language.go
223 lines (191 loc) · 5.01 KB
/
language.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
package main
import (
//TODO: change to gopher-lua and check licences(mit 4 go-lua)
"fmt"
"regexp"
"strconv"
"strings"
lua "github.com/yuin/gopher-lua"
)
var L *lua.LState
func GetLuaAccesible(s *Node, key string) lua.LValue {
switch key {
case "x":
return lua.LNumber(s.Pos.X)
case "y":
return lua.LNumber(s.Pos.Y)
}
return lua.LNil
}
func SetLuaAccesible(s *Node, key string, value lua.LValue) {
switch key {
case "x":
s.Pos.X = float32(value.(lua.LNumber))
case "y":
s.Pos.Y = float32(value.(lua.LNumber))
}
}
func SetPropertyL(l *lua.LState) int {
nodeTable := l.Get(1).(*lua.LTable)
idL := nodeTable.RawGet(lua.LString("id"))
ID, _ := strconv.Atoi(lua.LVAsString(idL))
if ID == -1 {
l.Push(lua.LString("wrong node path!"))
} else {
property := l.ToString(2)
SetLuaAccesible(NODES[ID], property, l.Get(3))
l.Push(lua.LString("test")) //temp
}
return 1
}
func GetPropertyL(l *lua.LState) int { //gets a property by id, string name and returns it as string
nodeTable := l.Get(1).(*lua.LTable)
idL := nodeTable.RawGet(lua.LString("id"))
ID, _ := strconv.Atoi(lua.LVAsString(idL))
if ID == -1 {
l.Push(lua.LString("wrong node path!"))
} else {
property := l.ToString(2)
result := GetLuaAccesible(NODES[ID], property)
l.Push(result)
}
return 1
}
func DoPathString(originID int, path string) (result string) {
var id int
if node := DoPath(NODES[originID], path); node != nil {
id = node.ID
} else {
id = -1
}
return fmt.Sprintf("NODES[%d]", id)
}
func DoPath(origin *Node, path string) (result *Node) { // implement this, relative to a node, path starts with $ maybe idk
//get path origin
pathLen := len(path)
var start int
if path[0] == '$' {
if pathLen > 1 && path[1] == '$' {
result = NODES[ROOT]
start = 2
if pathLen == 2 {
return
}
} else {
result = origin
start = 1
if pathLen == 1 {
return
}
}
} else {
panic("path string does not start with $ or $$: " + path)
}
path = path[start:]
if v, err := strconv.Atoi(path); err == nil {
result = NODES[v]
} else {
items := strings.Split(path, "/")
for _, v := range items {
if v == "*" { //could be ..
result = result.Parent
} else {
result = result.GetChildByName(v)
}
if result == nil {
return
}
}
}
return
}
//first it compiles paths to nodes[some_id], or better is just some_id
//it also needs a get function to get normal properties in lua
//so you can do stuff like
//self.a = get($child/grandchild, property_name)
//issue is paths outside get need to be table, and inside is ID
//either a special char like raw$child/grandchild, (probs best)
//then another node can do
//$*/*.a
//WATER PLANTS
func RunLua(ID int) string { //make nodes both run and addlua(done), just fixing node deletion and error handling
L.GetGlobal("NODES")
lFunc := L.GetGlobal("FUNCS").(*lua.LTable).RawGetInt(ID) //STORE FUNCTION IN NODE
err := L.CallByParam(lua.P{Fn: lFunc, NRet: 1, Protect: true})
var str string
if err != nil {
str = err.Error()
} else {
lStr, _ := L.Get(-1).(lua.LString)
str = lStr.String()
L.Pop(1)
}
return str
}
func RemoveLua(ID int) { //store the table
L.GetGlobal("FUNCS").(*lua.LTable).RawSetInt(ID, lua.LNil)
L.GetGlobal("NODES").(*lua.LTable).RawSetInt(ID, lua.LNil)
}
func StartLua() {
L = lua.NewState()
ResetLua()
L.SetGlobal("get", L.NewFunction(GetPropertyL))
L.SetGlobal("set", L.NewFunction(SetPropertyL))
}
func ResetLua() {
L.DoString("FUNCS = {}; NODES = {}")
}
func AddLua(n *Node, text string) {
code, hasCode := ParseCode(n.ID, text)
n.Flags.IsCode = hasCode
// if !hasCode {
// return
// }
precode := fmt.Sprintf(`NODES[%[1]d] = {id = %[1]d}
setmetatable(NODES[%[1]d], NODES[%[1]d])
NODES[%[1]d].__index = function(table, key)
value = get(NODES[%[1]d], key)
if value == nil then
return rawget(table, key)
else
return value
end
end
NODES[%[1]d].__newindex = function(table, key, value)
if set(NODES[%[1]d], key, value) == nil then
rawset(table, key, value)
end
end`, n.ID)
L.DoString(precode)
L.DoString(code)
}
func ParseCode(ID int, text string) (code string, hasCode bool) {
code = fmt.Sprintf(`
FUNCS[%[1]d] = function()
`, ID)
var proprepl = func(in string) string { return DoPathString(ID, in) }
re := regexp.MustCompile(`\$[\w/\*]*`) //replace paths with NODES[id]
ptext := text
text = re.ReplaceAllStringFunc(text, proprepl)
if ptext != text {
hasCode = true
}
extraCode := &[]string{}
var coderepl = func(in string) string { *extraCode = append(*extraCode, in[2:len(in)-2]); return "" }
re = regexp.MustCompile(`\|\|.*?\|\|`) //remove the ||expr||
ptext = text
text = re.ReplaceAllStringFunc(text, coderepl)
if ptext != text {
hasCode = true
}
re = regexp.MustCompile(`{{(.*?)}}|(NODES\S*)`) //do the tostring
ptext = text
text = re.ReplaceAllString(text, `]] .. tostring($1$2) .. [[`)
if ptext != text {
hasCode = true
}
text = "[[" + text + "]]"
code += " " + strings.Join(*extraCode, " ") + " "
code += fmt.Sprintf(`return %s end`, text) //add text to code
return
}