initial stage...
[yu.git] / yu / utils.lua
blob210d533fca48c7e3869462e50a1b6634b4ce69db
1 local ipairs,pairs=ipairs,pairs
2 module("yu",package.seeall)
4 function findModule(m)
5 if type(m)=='string' then
6 return m
7 else
8 local src=''
9 for i,s in ipairs(m) do
10 if i>1 then src=src..'/' end
11 src=src..'s'
12 end
13 return src
14 end
15 end
17 function unescape(s)
18 s=string.gsub(s,'\\(%d%d?%d?)',string.char)
19 s=string.gsub(s,'\\.',{
20 ['\\n']='\n',
21 ['\\t']='\t',
22 ['\\r']='\r',
23 ['\\b']='\b',
24 ['\\a']='\a',
25 ['\\v']='\v',
26 ['\\\\']='\\',
27 ['\\\'']='\'',
28 ['\\\"']='\"',
29 ['\\0']='\0'
31 return s
32 end
37 ----TOOL FUNCTIONS
38 local stackmt={}
39 function stackmt:push(d)
40 local s=self.stack
41 s[#s+1]=d
42 return d
43 end
45 function stackmt:pop()
46 local s=self.stack
47 local l=#s
48 local v=s[l]
49 s[l]=nil
50 return s[l-1]
51 end
53 function stackmt:peek(k)
54 local s=self.stack
55 return s[#s-(k or 0)]
56 end
58 function newStack()
59 return setmetatable({
60 stack={}
61 },{__index=stackmt})
62 end
65 function findLine(lineInfo,pos)
66 local off0=0
67 local l0=0
69 for l,off in ipairs(lineInfo) do
70 if pos>=off0 and pos<off then
71 return l0,pos-off0
72 end
73 off0=off
74 l0=l
75 end
76 return l0,pos-off0
77 end
79 function getTokenPosString(token,currentModule)
80 local pos=token.p0 or 0
81 local m=token.module or currentModule
82 local line,lpos=findLine(m.lineInfo,pos)
83 return "@"..m.file.."<"..line..":"..lpos..">"
84 end
86 function compileErr(msg,token,currentModule)
87 local errmsg="error"..(token and getTokenPosString(token,currentModule) or "")..":"..msg
88 print('----------COMPILE ERROR:')
89 print(errmsg)
90 return error('compile error')
91 end
95 function is(i,a,b,...)
96 if i==a then return true end
97 if b then return is(i,b,...) end
98 return false
99 end
101 ---------------------Token types
102 function isConst(c)
103 return is(c.tag,'number','boolean','string','nil')
106 function isDecl(b)
107 local tag=b.tag
108 return is(tag,"vardecl" ,"classdecl" ,"funcdecl" ,"enumdecl" ,"methoddecl"
109 ,"var","externfunc","externclass")
112 function isGlobalDecl(b)
113 local tag=b.tag
114 if tag=="vardecl" then
115 local vtype=b.vtype
116 return vtype=="global" or vtype=="const"
117 else
118 return is(tag, "classdecl" ,"funcdecl" ,"enumdecl" ,"methoddecl")
122 function isMemberDecl(d)
123 local tag=d.tag
124 return ((tag=='vardecl' or tag=='var') and d.vtype=='field') or tag=='methoddecl'
127 function isTypeDecl(t)
128 return is(t.tag,'classdecl','enumdecl','functype')
131 local function findExternModule(src,dst,checked)
132 if src==dst then return true end
133 checked[src]=true
134 for path,m in pairs(src.externModules) do
135 if not checked[m] and findExternModule(m,dst,checked) then
136 return true
139 return false
142 local _visibleCache={}
143 function isModuleVisible(src,dst)
144 local vis=src.visibleMods
145 if not vis then vis={} src.visibleMods=vis end
146 local v=vis[dst]
147 if v~=nil then return v end
148 v=findExternModule(src,dst,{})
149 vis[dst]=v
150 return v
153 local function getConstNode(n)
154 local tag=n.tag
155 if is(tag,'string','nil','number') then return n end
156 if tag=='var' and n.vtype=='const' then return getConstNode(n.value) end
157 if is(tag,'varacc','member') then
158 local decl=n.decl
159 if decl then return getConstNode(decl) end
161 if tag=='enumitem' then
162 return getConstNode(n.value)
165 return nil
168 local function getConst(n)
169 local tag=n.tag
170 if tag=='string' then return string.format('%q',yu.unescape(n.v)) end
171 if tag=='nil' then return 'nil' end
172 if tag=='number' or tag=='boolean' then return n.v end
173 error('non const:'..tag)
176 local function getDeclName(d)
177 local tag=d.tag
178 if tag=='var' then
179 local vtype=d.vtype
180 if vtype=='local' then return d.name end
181 if vtype=='global' then return d.fullname end
182 if vtype=='const' then return getConst(d.value) end
183 if vtype=='field' then
184 --TODO: self?
185 return d.fullname
187 elseif tag=='funcdecl' then
188 --TODO:....
189 elseif tag=='arg' then
190 return d.name
192 return d.fullname
196 local opPrecedence={
197 {'and','or'},
198 {'>','<','>=','<=','==','~='},
199 {'..'},
200 {'+','-'},
201 {'*','/','^','%'}
204 local opClass={
205 ['+']='arith',
206 ['-']='arith',
207 ['*']='arith',
208 ['/']='arith',
209 ['%']='arith',
210 ['^']='arith',
212 ['..']='concat',
214 ['>']='order',
215 ['<']='order',
216 ['>=']='order',
217 ['<=']='order',
219 ['==']='equal',
220 ['~=']='equal',
222 ['and']='logic',
223 ['or']='logic',
224 ['not']='logic',
227 function getOpPrecedence(op)
228 for i,s in ipairs(opPrecedence) do
229 for j,o in ipairs(s) do
230 if op==o then return i end
233 return error("unknown op:"..op)
236 function getOpClass(op)
237 return opClass[op]
240 _M.getConstNode=getConstNode
241 _M.getConst=getConst
242 _M.getDeclName=getDeclName