Mercurial Hosting > luan
comparison src/luan/Luan.java @ 1333:25746915a241
merge Luan and LuanState
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 12 Feb 2019 22:33:40 -0700 |
parents | f41919741100 |
children | c88b486a9511 |
comparison
equal
deleted
inserted
replaced
1332:11b7e11f9ed5 | 1333:25746915a241 |
---|---|
1 package luan; | 1 package luan; |
2 | 2 |
3 import java.lang.reflect.Array; | |
4 import java.io.Closeable; | |
3 import java.util.List; | 5 import java.util.List; |
4 import java.util.ArrayList; | 6 import java.util.ArrayList; |
5 import java.util.Map; | 7 import java.util.Map; |
8 import java.util.HashMap; | |
6 import java.util.LinkedHashMap; | 9 import java.util.LinkedHashMap; |
10 import java.util.Iterator; | |
11 import java.util.Arrays; | |
7 import java.util.Set; | 12 import java.util.Set; |
8 import java.util.Arrays; | 13 import org.slf4j.Logger; |
9 import java.util.Iterator; | 14 import org.slf4j.LoggerFactory; |
10 import luan.modules.BasicLuan; | 15 import luan.modules.BasicLuan; |
11 import luan.modules.Utils; | 16 import luan.modules.JavaLuan; |
17 import luan.modules.PackageLuan; | |
12 import luan.impl.LuanCompiler; | 18 import luan.impl.LuanCompiler; |
13 | 19 |
14 | 20 |
15 public final class Luan { | 21 public final class Luan implements LuanCloneable { |
22 private static final Logger logger = LoggerFactory.getLogger(Luan.class); | |
23 | |
24 private final List<LuanClosure> stack = new ArrayList<LuanClosure>(); | |
25 private Map registry; | |
26 public boolean isLocked = false; | |
27 | |
28 public interface OnClose extends Closeable { | |
29 public void onClose(Closeable c); | |
30 } | |
31 public OnClose onClose; | |
32 | |
33 public Luan() { | |
34 registry = new HashMap(); | |
35 } | |
36 | |
37 private Luan(Luan luan) {} | |
38 | |
39 @Override public Luan shallowClone() { | |
40 return new Luan(this); | |
41 } | |
42 | |
43 @Override public void deepenClone(LuanCloneable dc,LuanCloner cloner) { | |
44 Luan clone = (Luan)dc; | |
45 clone.registry = cloner.clone(registry); | |
46 if( cloner.type == LuanCloner.Type.INCREMENTAL ) | |
47 isLocked = true; | |
48 } | |
49 | |
50 public LuanClosure peek() { | |
51 return peek(1); | |
52 } | |
53 | |
54 public LuanClosure peek(int i) { | |
55 int n = stack.size(); | |
56 return n < i ? null : stack.get(n-i); | |
57 } | |
58 | |
59 void push(LuanClosure closure) { | |
60 stack.add(closure); | |
61 } | |
62 | |
63 void pop() { | |
64 stack.remove(stack.size()-1); | |
65 } | |
66 | |
67 public Map registry() { | |
68 return registry; | |
69 } | |
70 | |
71 public void onClose(Closeable c) { | |
72 if( onClose != null ) | |
73 onClose.onClose(c); | |
74 } | |
75 | |
76 public Object eval(String cmd,Object... args) throws LuanException { | |
77 return Luan.load(cmd,"eval").call(this,args); | |
78 } | |
79 | |
80 public Object require(String modName) throws LuanException { | |
81 return PackageLuan.require(this,modName); | |
82 } | |
83 | |
84 public String toString(Object obj) throws LuanException { | |
85 if( obj instanceof LuanTable ) { | |
86 LuanTable tbl = (LuanTable)obj; | |
87 return tbl.toStringLuan(); | |
88 } | |
89 if( obj == null ) | |
90 return "nil"; | |
91 if( obj instanceof Number ) | |
92 return Luan.toString((Number)obj); | |
93 if( obj instanceof byte[] ) | |
94 return "binary: " + Integer.toHexString(obj.hashCode()); | |
95 return obj.toString(); | |
96 } | |
97 | |
98 public Object index(Object obj,Object key) throws LuanException { | |
99 if( obj instanceof LuanTable ) { | |
100 LuanTable tbl = (LuanTable)obj; | |
101 return tbl.get(key); | |
102 } | |
103 if( obj != null && peek().javaOk ) | |
104 return JavaLuan.__index(this,obj,key); | |
105 throw new LuanException("attempt to index a " + Luan.type(obj) + " value" ); | |
106 } | |
107 | |
108 | |
109 public boolean isLessThan(Object o1,Object o2) throws LuanException { | |
110 if( o1 instanceof Number && o2 instanceof Number ) { | |
111 Number n1 = (Number)o1; | |
112 Number n2 = (Number)o2; | |
113 return n1.doubleValue() < n2.doubleValue(); | |
114 } | |
115 if( o1 instanceof String && o2 instanceof String ) { | |
116 String s1 = (String)o1; | |
117 String s2 = (String)o2; | |
118 return s1.compareTo(s2) < 0; | |
119 } | |
120 LuanFunction fn = getBinHandler("__lt",o1,o2); | |
121 if( fn != null ) | |
122 return Luan.checkBoolean( Luan.first(fn.call(this,new Object[]{o1,o2})) ); | |
123 throw new LuanException( "attempt to compare " + Luan.type(o1) + " with " + Luan.type(o2) ); | |
124 } | |
125 | |
126 public LuanFunction getBinHandler(String op,Object o1,Object o2) throws LuanException { | |
127 if( o1 instanceof LuanTable ) { | |
128 LuanFunction f1 = getHandlerFunction(op,(LuanTable)o1); | |
129 if( f1 != null ) | |
130 return f1; | |
131 } | |
132 return o2 instanceof LuanTable ? getHandlerFunction(op,(LuanTable)o2) : null; | |
133 } | |
134 | |
135 public LuanFunction getHandlerFunction(String op,LuanTable t) throws LuanException { | |
136 Object f = t.getHandler(op); | |
137 if( f == null ) | |
138 return null; | |
139 return Luan.checkFunction(f); | |
140 } | |
141 | |
142 public LuanTable toTable(Object obj) { | |
143 if( obj == null ) | |
144 return null; | |
145 if( obj instanceof LuanTable ) | |
146 return (LuanTable)obj; | |
147 if( obj instanceof List ) { | |
148 return new LuanTable(this,(List)obj); | |
149 } | |
150 if( obj instanceof Map ) { | |
151 return new LuanTable(this,(Map)obj); | |
152 } | |
153 if( obj instanceof Set ) { | |
154 return new LuanTable(this,(Set)obj); | |
155 } | |
156 Class cls = obj.getClass(); | |
157 if( cls.isArray() ) { | |
158 if( cls.getComponentType().isPrimitive() ) { | |
159 int len = Array.getLength(obj); | |
160 List list = new ArrayList(); | |
161 for( int i=0; i<len; i++ ) { | |
162 list.add(Array.get(obj,i)); | |
163 } | |
164 return new LuanTable(this,list); | |
165 } else { | |
166 Object[] a = (Object[])obj; | |
167 return new LuanTable(this,Arrays.asList(a)); | |
168 } | |
169 } | |
170 return null; | |
171 } | |
172 | |
173 | |
174 | |
175 // static | |
16 | 176 |
17 public static void main(String[] args) throws LuanException { | 177 public static void main(String[] args) throws LuanException { |
18 doFile( "classpath:luan/cmd_line.luan", args ); | 178 doFile( "classpath:luan/cmd_line.luan", args ); |
19 } | 179 } |
20 | 180 |
21 public static void doFile(String uri,String... args) throws LuanException { | 181 public static void doFile(String uri,String... args) throws LuanException { |
22 LuanState luan = new LuanState(); | 182 Luan luan = new Luan(); |
23 LuanFunction fn = (LuanFunction)BasicLuan.load_file(luan,uri); | 183 LuanFunction fn = (LuanFunction)BasicLuan.load_file(luan,uri); |
24 fn.call(luan,args); | 184 fn.call(luan,args); |
25 } | 185 } |
26 | 186 |
27 public static Object first(Object obj) { | 187 public static Object first(Object obj) { |
96 s = s.replace("\'","\\'"); | 256 s = s.replace("\'","\\'"); |
97 return s; | 257 return s; |
98 } | 258 } |
99 | 259 |
100 | 260 |
101 // from LuanState | |
102 | |
103 public static Boolean checkBoolean(Object obj) throws LuanException { | 261 public static Boolean checkBoolean(Object obj) throws LuanException { |
104 if( obj instanceof Boolean ) | 262 if( obj instanceof Boolean ) |
105 return (Boolean)obj; | 263 return (Boolean)obj; |
106 throw new LuanException("attempt to use a " + Luan.type(obj) + " value as a boolean" ); | 264 throw new LuanException("attempt to use a " + Luan.type(obj) + " value as a boolean" ); |
107 } | 265 } |
127 public static LuanFunction load(String text,String sourceName) | 285 public static LuanFunction load(String text,String sourceName) |
128 throws LuanException | 286 throws LuanException |
129 { | 287 { |
130 return load(text,sourceName,null); | 288 return load(text,sourceName,null); |
131 } | 289 } |
132 | |
133 /* | |
134 public static Object toLuan(Object obj) throws LuanException { | |
135 if( !type(obj).equals("java") ) | |
136 return obj; | |
137 LuanTable tbl = new LuanTable(); | |
138 if( obj instanceof Map ) { | |
139 Map map = (Map)obj; | |
140 for( Object stupid : map.entrySet() ) { | |
141 Map.Entry entry = (Map.Entry)stupid; | |
142 Object key = entry.getKey(); | |
143 Object value = entry.getValue(); | |
144 if( key != null && value != null ) | |
145 tbl.rawPut(toLuan(key),toLuan(value)); | |
146 } | |
147 return tbl; | |
148 } | |
149 if( obj instanceof Set ) { | |
150 Set set = (Set)obj; | |
151 for( Object el : set ) { | |
152 if( el != null ) | |
153 tbl.rawPut(toLuan(el),Boolean.TRUE); | |
154 } | |
155 return tbl; | |
156 } | |
157 List list; | |
158 if( obj instanceof List ) { | |
159 list = (List)obj; | |
160 } else { | |
161 Class cls = obj.getClass(); | |
162 if( cls.isArray() && !cls.getComponentType().isPrimitive() ) { | |
163 Object[] a = (Object[])obj; | |
164 list = Arrays.asList(a); | |
165 } else | |
166 throw new LuanException("can't convert type "+obj.getClass().getName()+" to luan"); | |
167 } | |
168 int n = list.size(); | |
169 for( int i=0; i<n; i++ ) { | |
170 Object val = list.get(i); | |
171 if( val != null ) | |
172 tbl.rawPut(i+1,toLuan(val)); | |
173 } | |
174 return tbl; | |
175 } | |
176 */ | |
177 | 290 |
178 public static Object toJava(Object obj) throws LuanException { | 291 public static Object toJava(Object obj) throws LuanException { |
179 if( !(obj instanceof LuanTable) ) | 292 if( !(obj instanceof LuanTable) ) |
180 return obj; | 293 return obj; |
181 LuanTable tbl = (LuanTable)obj; | 294 LuanTable tbl = (LuanTable)obj; |
193 map.put( toJava(entry.getKey()), toJava(entry.getValue()) ); | 306 map.put( toJava(entry.getKey()), toJava(entry.getValue()) ); |
194 } | 307 } |
195 return map; | 308 return map; |
196 } | 309 } |
197 } | 310 } |
198 /* | |
199 public static LuanTable table(LuanTable v) throws LuanException { | |
200 Utils.checkNotNull(v); | |
201 return v; | |
202 } | |
203 */ | |
204 | |
205 | 311 |
206 | 312 |
207 // security | 313 // security |
208 | 314 |
209 public interface Security { | 315 public interface Security { |
210 public void check(LuanState luan,LuanClosure closure,String op,Object... args) throws LuanException; | 316 public void check(Luan luan,LuanClosure closure,String op,Object... args) throws LuanException; |
211 } | 317 } |
212 | 318 |
213 private static String SECURITY_KEY = "Luan.Security"; | 319 private static String SECURITY_KEY = "Luan.Security"; |
214 | 320 |
215 public static void checkSecurity(LuanState luan,String op,Object... args) throws LuanException { | 321 public static void checkSecurity(Luan luan,String op,Object... args) throws LuanException { |
216 check(luan,1,op,args); | 322 check(luan,1,op,args); |
217 } | 323 } |
218 | 324 |
219 public static void checkCallerSecurity(LuanState luan,String op,Object... args) throws LuanException { | 325 public static void checkCallerSecurity(Luan luan,String op,Object... args) throws LuanException { |
220 check(luan,2,op,args); | 326 check(luan,2,op,args); |
221 } | 327 } |
222 | 328 |
223 private static void check(LuanState luan,int i,String op,Object... args) throws LuanException { | 329 private static void check(Luan luan,int i,String op,Object... args) throws LuanException { |
224 Security s = (Security)luan.registry().get(SECURITY_KEY); | 330 Security s = (Security)luan.registry().get(SECURITY_KEY); |
225 if( s!=null ) | 331 if( s!=null ) |
226 s.check(luan,luan.peek(),op,args); | 332 s.check(luan,luan.peek(),op,args); |
227 } | 333 } |
228 | 334 |
229 public static Security setSecurity(LuanState luan,Security s) { | 335 public static Security setSecurity(Luan luan,Security s) { |
230 return (Security)luan.registry().put(SECURITY_KEY,s); | 336 return (Security)luan.registry().put(SECURITY_KEY,s); |
231 } | 337 } |
232 | 338 |
233 | |
234 private Luan() {} // never | |
235 } | 339 } |