1 package jfun.yan.xml; 2 3 import java.beans.PropertyDescriptor ; 4 import java.io.File ; 5 import java.lang.reflect.Array ; 6 import java.lang.reflect.InvocationTargetException ; 7 import java.lang.reflect.Method ; 8 import java.util.ArrayList ; 9 import java.util.Collection ; 10 import java.util.HashMap ; 11 import java.util.HashSet ; 12 import java.util.List ; 13 import java.util.Map ; 14 import java.util.Set ; 15 16 17 import jfun.util.Misc; 18 import jfun.util.StringUtils; 19 import jfun.util.dict.Dict; 20 import jfun.yan.Binder; 21 import jfun.yan.Component; 22 import jfun.yan.ComponentBinder; 23 import jfun.yan.Components; 24 import jfun.yan.Creator; 25 import jfun.yan.DelegatingComponent; 26 import jfun.yan.Dependency; 27 import jfun.yan.Monad; 28 import jfun.yan.ParameterBinder; 29 import jfun.yan.PropertyBinder; 30 import jfun.yan.Verifiable; 31 import jfun.yan.lifecycle.DefaultLifecycleManager; 32 import jfun.yan.util.ReflectionUtil; 33 import jfun.yan.util.Utils; 34 import jfun.yan.util.deserializer.Deserializer; 35 import jfun.yan.util.resource.ResourceLoader; 36 import jfun.yan.xml.nut.Nut; 37 import jfun.yan.xml.nut.NutDescriptor; 38 39 47 class BodyCompiler extends Constants 48 implements NutEnvironment, Converter, java.io.Serializable { 49 50 private static final Set sys_attributes = MyUtil.getNameSet( 51 new String []{ 52 ID, VAR, SINGLETON, 53 TYPE, AUTOWIRE, SYNCHRONIZED, EAGER_INSTANTIATED, EAGER_INSTANTIATED2 54 } 55 ); 56 private static final Set fun_attributes = MyUtil.getNameSet( 58 new String []{ 59 ID, PARAMS, SYNCHRONIZED 60 } 61 ); 62 private static final Set callcc_attributes = MyUtil.getNameSet( 63 new String []{ 64 ID, VAR, SINGLETON, 65 TYPE, SYNCHRONIZED, EXIT 66 } 67 ); 68 private static final Set bare_attributes = MyUtil.getNameSet(new String []{ 69 ID, VAR 70 }); 71 private final Map nut_descriptors; 72 private final WiringMode defaults; 76 private final Interpreter interpreter; 78 private final Set reserves; 79 private final Object module_id; 80 private final boolean default_eager_mode; 81 83 public ParameterBinder getParameterWiringMode(String mode_name, Location loc) { 84 return MyUtil.autocast(MyUtil.getParamWiring(mode_name, getCustomWiringModes(), 85 loc, defaults.getParameterWiring()), 86 loc, this); 87 } 88 89 public PropertyBinder getPropertyWiringMode(String mode_name, Location loc) { 90 return MyUtil.autocast( 91 MyUtil.getPropWiring(mode_name, getCustomWiringModes(), 92 loc, defaults.getPropertyWiring()), 93 loc, this); 94 } 95 96 BodyCompiler(Interpreter interpreter, Object module_id, 97 Map nut_descriptors, String list_separator, String map_separator, 98 WiringMode defaults, Set reserves, final boolean eager_default) { 100 this.interpreter = interpreter; 101 this.module_id = module_id; 102 this.nut_descriptors = nut_descriptors; 106 this.list_separator = list_separator; 107 this.map_separator = map_separator; 108 this.defaults = defaults; 109 this.reserves = reserves; 111 this.default_eager_mode = eager_default; 112 } 114 115 public Statements compileStatements( 116 final Tag thistag, 117 final Dict initial_ctxt, 118 final IdChecker idchecker, 119 final String tagname, 120 List nodes){ 121 final LocalScope scope = compileLocalScope( 123 tagname, initial_ctxt, nodes, idchecker, 124 defaults.getSingletonMode(), true); 125 final Object [] keys = scope.getKeys(); 126 final Stmt[] stmts = scope.getDefinitions(); 127 return new Statements(keys, stmts); 128 } 129 private final String list_separator; 130 private final String map_separator; 131 private ConfigurationException raiseTypeMismatch(Class type, Object v, Location loc){ 132 throw new ConfigurationException(Misc.getTypeName(type)+" expected, while " 133 +(v==null?"null":Misc.getTypeName(v.getClass())) 134 +" encountered.", loc); 135 } 136 private Object fromList(Class type, List ll, Location loc) 137 throws IllegalAccessException , InstantiationException , 138 InvocationTargetException { 139 final int sz = ll.size(); 140 if(isListType(type)){ 141 final List result = Utils.createList(type, sz); 142 result.addAll(ll); 143 return result; 144 } 145 else if(Set .class.isAssignableFrom(type)){ 146 final Set result = Utils.createSet(type, sz); 147 for(int i=0; i<sz; i++){ 148 final Object elem = ll.get(i); 149 if(result.contains(elem)){ 150 throw new ConfigurationException("duplicate set element: "+elem, loc); 151 } 152 result.add(elem); 153 } 154 return result; 155 } 156 else if(type.isArray()){ 157 final Class etype = type.getComponentType(); 158 final Object result = Array.newInstance(etype, sz); 159 for(int i=0; i<sz; i++){ 160 final Object elem = convert(etype, ll.get(i), loc); 161 Array.set(result, i, elem); 162 } 163 return result; 164 } 165 return null; 166 } 167 private Object cast(Class type, Object obj, Location loc) 168 throws IllegalAccessException , InstantiationException , 169 InvocationTargetException { 170 if(Component.class.equals(type)){ 171 return NutsUtils.asComponent(obj); 172 } 173 else if(obj instanceof ListLiteral){ 174 final Object result = fromList(type, (ListLiteral)obj, loc); 175 if(result != null) return result; 176 } 177 else if(obj instanceof MapLiteral){ 178 final MapLiteral ml = (MapLiteral)obj; 179 final int sz = ml.size(); 180 if(Map .class.isAssignableFrom(type)){ 181 final Map result = Utils.createMap(type, sz); 182 final Object [] keys = ml.getKeys(); 183 for(int i=0; i<keys.length; i++){ 184 final Object key = keys[i]; 185 final Object val = ml.get(key); 186 result.put(key, val); 187 } 188 return result; 189 } 190 } 191 else if(type.isArray()){ 192 final Class elemtype = type.getComponentType(); 193 return MyUtil.toArray(elemtype, convert(elemtype, obj, loc)); 194 } 195 else if(List .class.isAssignableFrom(type) || Collection .class.equals(type)){ 196 return MyUtil.toList(type, obj); 197 } 198 else if(Set .class.isAssignableFrom(type)){ 199 return MyUtil.toSet(type, obj); 200 } 201 throw raiseTypeMismatch(type, obj, loc); 202 } 203 public Component cast(final Class target_type, Component c, 204 final Location loc){ 205 return MyUtil.cast(target_type, c, loc, this); 206 } 207 public Object convert(Class expected, Object obj, Location loc){ 208 if(expected==null) return obj; 209 if(ReflectionUtil.isInstance(expected, obj)){ 210 return obj; 211 } 212 else if(String .class.equals(expected)){ 213 if(obj instanceof Literal){ 214 return ((Literal)obj).toText(); 215 } 216 else return obj.toString(); 217 } 218 else if(obj instanceof String ){ 219 try{ 220 return convertLiteral(expected, (String )obj, loc); 221 } 222 catch(Throwable e){ 223 throw raise(e, loc); 224 } 225 } 226 try{ 227 return cast(expected, obj, loc); 228 } 229 catch(Throwable e){ 230 throw raise(e, loc); 231 } 232 } 233 private Object convertLiteral(Class type, String str, Location loc) 234 throws Exception { 235 if(type.isInstance(str)) return str; 236 str = str.trim(); 237 if(isCompoundType(type)){ 238 final String [] subs = NutsUtils.split(str, list_separator); 239 final List sublist = Utils.asList(subs); 240 final Object result = fromList(type, sublist, loc); 241 if(result != null) return result; 242 } 243 else if(Map .class.isAssignableFrom(type)){ 244 if(!(str.startsWith("{") && str.endsWith("}"))){ 245 throw new IllegalArgumentException ("map literal has to be enclosed with {}"); 246 } 247 str = str.substring(1, str.length()-1); 248 final String [] entries = NutsUtils.split(str, map_separator); 249 final Map map = jfun.yan.util.Utils.createMap(type, entries.length); 250 for(int i=0; i<entries.length; i++){ 251 final String entry = entries[i]; 252 final int delimit = entry.indexOf('='); 253 if(delimit<0){ 254 throw new IllegalArgumentException ("'=' is required for each map entry."); 255 } 256 final String key = entry.substring(0, delimit).trim(); 257 if(map.containsKey(key)){ 258 throw new IllegalArgumentException ("duplicate map key: "+key); 259 } 260 final String val = entry.substring(delimit+1, entry.length()); 261 map.put(key, val); 262 } 263 return map; 264 } 265 275 try{ 276 return deserialize(type, str); 277 } 278 catch(Throwable e){ 279 throw raise("failed to convert string to "+Misc.getTypeName(type), e, loc); 280 } 281 } 282 283 private String getIdAttribute(Tag tag){ 284 return getWord(tag, ID); 285 } 286 private String getVarAttribute(Tag tag){ 287 return getWord(tag, VAR); 288 } 289 private void checkWord(String word, String kind, Location loc){ 290 if(word!=null && !NutsUtils.isValidId(word)){ 291 throw new ConfigurationException("invalid "+kind, loc); 292 } 293 if(reserves.contains(word)){ 294 throw new ConfigurationException(kind+" "+word+" is a reserved word.", 295 loc); 296 } 297 } 298 private String getWord(Tag tag, String kind){ 299 final String word = tag.getAttribute(kind); 300 checkWord(word, kind, tag.getLocation()); 301 return word; 302 303 } 304 private String getMandatoryVar(Tag tag){ 305 final String var = getVarAttribute(tag); 306 if(var==null) 307 throw new ConfigurationException("missing mandatory "+VAR, 308 tag.getLocation()); 309 return var; 310 } 311 private static Dict declareName(Dict ctxt, String name, Location loc){ 312 return ctxt.put(name, new Bound(name, loc)); 313 } 314 static class CurrentLocation extends ThreadLocal { 315 public Location getLocation(){ 316 return (Location)this.get(); 317 } 318 public void setLocation(Location loc){ 319 this.set(loc); 320 } 321 } 322 static CurrentLocation current_location = new CurrentLocation(); 323 private final class TagCompiler{ 324 private final int ind; 325 private final Dict ctxt; 326 private final Tag tag; 327 private final SingletonMode singleton_mode; 328 private final boolean var_permitted; 329 private final boolean is_global; 330 TagCompiler(int ind, Dict ctxt, Tag tag, 331 SingletonMode singleton_mode, boolean var_permitted, 332 boolean is_global) { 333 this.ind = ind; 334 this.ctxt = ctxt; 335 this.tag = tag; 336 this.singleton_mode = singleton_mode; 337 this.var_permitted = var_permitted; 338 this.is_global = is_global; 339 } 340 public Location getLocation(){ 341 return tag.getLocation(); 342 } 343 public String getName(){ 344 return tag.getName(); 345 } 346 private String getErrorMessage(String tagname, String msg){ 347 return "<"+tagname+"> - "+msg; 348 } 349 private ConfigurationException raise(String msg){ 350 throw new ConfigurationException(getErrorMessage(getName(), msg), tag.getLocation()); 351 } 352 353 private ConfigurationException raise(Throwable e){ 354 if(e instanceof ConfigurationException){ 355 throw (ConfigurationException)e; 356 } 357 else if(e instanceof InvocationTargetException ){ 358 return raise(((InvocationTargetException )e).getTargetException()); 359 } 360 throw new ConfigurationException(getErrorMessage(getName(), e.getMessage()), e, tag.getLocation()); 361 } 362 private ConfigurationException raise(Throwable e, Location loc){ 363 return BodyCompiler.raise(e, loc); 364 } 365 public String getAttribute(String name){ 366 return tag.getAttribute(name); 367 } 368 private void assertAttributes(Set table){ 369 MyUtil.assertAttributes(tag, table); 370 } 371 private Dict declareNames(Dict ctxt, String [] names){ 372 final Stmt[] stmts = new Stmt[names.length]; 373 final Set cache = new HashSet (names.length); 374 for(int i=0; i<names.length; i++){ 375 final String name = names[i]; 376 if(cache.contains(name)){ 377 throw raise("duplicate parameter name: "+name); 378 } 379 cache.add(name); 380 checkWord(name, "parameter name", getLocation()); 381 stmts[i] = new Bound(names[i], getLocation()); 382 } 383 return ctxt.puts(names, stmts); 384 } 385 private Stmt compile(){ 386 current_location.setLocation(getLocation()); 387 final List subnodes = tag.getSubNodes(); 388 Dict ctxt = this.ctxt; 389 if(BINDER.equals(tag.getName())){ 390 final String varname = getMandatoryVar(this.tag); 391 ctxt = declareName(ctxt, varname, getLocation()); 392 } 393 else if(FUNCTION.equals(tag.getName())){ 394 final String paramnames = MyUtil.getMandatory(tag, PARAMS) 395 .trim(); 396 final String [] params = NutsUtils.split(paramnames, list_separator); 397 400 ctxt = declareNames(ctxt, params); 401 } 402 if(subnodes.isEmpty()){ 403 return compileMe(ctxt, subnodes); 404 } 405 else{ 406 final Node node = (Node)subnodes.get(0); 407 if(node instanceof Tag){ 408 final Tag t = (Tag)node; 409 if(LOCAL.equals(t.getName())){ 410 final LocalScope scope = compileLocalScope(ctxt, t); 411 return withScope(scope, compileMe(scope.getScope(), 412 subnodes.subList(1, subnodes.size())), getLocation()); 413 } 414 } 415 return compileMe(ctxt, subnodes); 416 } 417 } 418 419 private Stmt wrapStmt(final Dict local_ctxt, final Stmt stmt){ 420 final Stmt type = getTypeAttribute(local_ctxt); 422 final Stmt wiring = getAutowireAttribute(local_ctxt, defaults.getParameterWiring()); 423 final Stmt singleton_mode = getSingletonAttribute(local_ctxt, this.singleton_mode); 424 final Stmt sync_stmt = getSynchronizedAttribute(local_ctxt); 425 final Stmt eager = is_global?getEagerInstantiationAttribute(local_ctxt):null; 426 final String id = getAttribute(ID); 427 final Location loc = stmt.getLocation(); 428 return new Stmt(){ 429 public String toString(){ 430 return stmt.toString(); 431 } 432 public Object run(Dict frame, Runtime runtime){ 433 Object obj = stmt.run(frame, runtime); 434 final Class casttype = 435 type==null?null:(Class )type.run(frame, runtime); 436 final ParameterBinder autowire = 437 wiring==null?null:(ParameterBinder)wiring.run(frame, runtime); 438 final SingletonMode singleton = 439 singleton_mode==null?null: 440 (SingletonMode)singleton_mode.run(frame, runtime); 441 final boolean sync = sync_stmt==null?false: 442 ((Boolean )sync_stmt.run(frame, runtime)).booleanValue(); 443 if(obj instanceof Creator){ 444 final Component result = MyUtil.wrapComponent( 445 Components.adapt((Creator)obj), runtime, loc, 446 casttype, singleton, autowire, sync, BodyCompiler.this); 447 if(eager!=null){ 448 final boolean eagerly_instantiated = 449 ((Boolean )eager.run(frame, runtime)).booleanValue(); 450 if(eagerly_instantiated){ 451 registerEagerInstantiation(ind, id, result); 452 } 453 } 454 return result; 455 } 456 else{ 457 if(sync && obj instanceof NutsFunction){ 458 obj = new SynchronizedNutsFunction((NutsFunction)obj); 459 } 460 if(casttype != null){ 461 try{ 462 return convert(casttype, obj, loc); 463 } 464 catch(Throwable e){ 465 throw raise(e, loc); 466 } 467 } 468 else return obj; 469 } 470 } 471 public Location getLocation(){ 472 return loc; 473 } 474 public Class getType(){ 475 return stmt.getType(); 476 } 477 }; 478 } 479 480 private Stmt compileMe(Dict local_ctxt, List nodes){ 481 return wrapStmt(local_ctxt, compileTagBody(local_ctxt, nodes)); 482 } 483 private Stmt compileTagBody(Dict local_ctxt, List nodes){ 484 final String name = tag.getName(); 485 if(SEQUENCE.equals(name)){ 487 return compileSequence(local_ctxt, nodes); 488 } 489 else if(BINDER.equals(name)){ 490 return compileBinder(local_ctxt, nodes); 491 } 492 else if(FUNCTION.equals(name)){ 493 return compileFunction(local_ctxt, nodes); 494 } 495 else if(CALLCC.equals(name)){ 496 return compileCallcc(local_ctxt, nodes); 497 } 498 else{ 499 final NutDescriptor desc = (NutDescriptor)nut_descriptors.get(name); 500 if(desc == null){ 501 throw raise("unknown nut"); 502 } 503 return compileNut(name, desc, local_ctxt, nodes, false); 504 } 505 } 506 private Stmt compileFunction(Dict ctxt, List nodes){ 507 assertAttributes(fun_attributes); 508 final int sz = nodes.size(); 509 if(sz==0){ 510 throw raise("empty function not allowed."); 511 } 512 else if(sz>1){ 513 throw raise("only one sub-element is allowed."); 514 } 515 final String [] params = StringUtils.split( 516 MyUtil.getMandatory(tag, PARAMS), 517 list_separator); 518 final String fname = getIdAttribute(tag); 519 final String funname = fname==null?"\\":fname; 520 final Stmt body = compileNode(0, ctxt, (Node)nodes.get(0), false); 524 final Location loc = getLocation(); 525 return new Stmt(){ 526 public Class getType() { 527 return NutsFunction.class; 528 } 529 public Object run(final Dict frame, final Runtime runtime) { 530 return new NutsFunction(){ 531 public Class getReturnType(){ 532 return body.getType(); 533 } 534 public Object call(Object [] args) { 535 return body.run(frame.puts(params, args), runtime); 536 } 537 public String getName() { 538 return funname+StringUtils.listArray("(",",",")",params); 539 } 540 public int getParameterCount() { 541 return params.length; 542 } 543 public String [] getParameterNames(){ 544 return (String [])params.clone(); 545 } 546 public Location getLocation() { 547 return loc; 548 } 549 public String toString() { 550 return funname; 551 } 552 }; 553 } 554 public Location getLocation() { 555 return loc; 556 } 557 public String toString(){ 558 return funname+StringUtils.listArray("(",",",")",params); 559 } 560 }; 561 } 562 private SideEffect property_setter(final PropertyDescriptor prop, 563 final Stmt stmt){ 564 return dyn_method_invoker(prop.getWriteMethod(), prop.getPropertyType(), stmt); 565 } 566 private SideEffect literal_property_setter(final PropertyDescriptor prop, 567 final String val){ 568 try{ 569 return method_invoker(prop.getWriteMethod(), 570 prop.getPropertyType(), val, getLocation()); 571 } 572 catch(Throwable e){ 573 throw raise(e); 574 } 575 } 576 private SideEffect method_invoker(final Method mtd, 577 final Class param_type, final String val, final Location loc){ 578 return new SideEffect(){ 579 public void apply(Object obj, Dict ctxt, Runtime runtime){ 580 try{ 581 mtd.invoke(obj, new Object []{convertLiteral(param_type, val, loc)}); 582 } 583 catch(Throwable e){ 584 throw raise(e); 585 } 586 } 587 public String toString(){ 588 return mtd.getName()+"("+val+")"; 589 } 590 }; 591 } 592 private Stmt compileNut(final String nutname,final NutDescriptor desc, 593 boolean is_subnut){ 594 final List subnodes = tag.getSubNodes(); 595 if(subnodes.isEmpty()){ 596 return compileNut(nutname, desc, ctxt, subnodes, is_subnut); 597 } 598 else{ 599 final Node node = (Node)subnodes.get(0); 600 if(node instanceof Tag){ 601 final Tag t = (Tag)node; 602 if(LOCAL.equals(t.getName())){ 603 final LocalScope scope = compileLocalScope(ctxt, t); 604 final Dict nctxt = scope.getScope(); 605 return withScope(scope, compileNut(nutname, desc, nctxt, 606 subnodes.subList(1, subnodes.size()), is_subnut), getLocation()); 607 } 608 } 609 return compileNut(nutname, desc, ctxt, subnodes, is_subnut); 610 } 611 } 612 619 private Stmt compileLiteralValue(Class expected_type, 620 Dict local_ctxt, String literal){ 621 if(literal==null) return null; 622 if(MyUtil.isRefName(literal)){ 623 final Stmt stmt = compileRefSymbol(literal, local_ctxt); 624 return cast(expected_type, stmt); 625 } 626 else{ 627 final Location loc = getLocation(); 628 final Object literal_val = StringInterpolator.interpolate(literal, local_ctxt, loc); 629 if(literal_val instanceof Stmt){ 630 return cast(expected_type, (Stmt)literal_val); 631 } 632 else return MyUtil.typedValue(expected_type, literal_val, loc, BodyCompiler.this); 633 } 634 } 635 636 646 private Stmt compileLiteralString(final Class type, String literal, 647 final FromLiteral fl, 648 Dict local_ctxt, final Location loc){ 649 if(MyUtil.isRefName(literal)){ 650 final Stmt stmt = compileRefSymbol(literal, local_ctxt); 651 return transformLiteralString(fl, type, stmt, loc); 652 } 653 else{ 654 final Object literal_val = StringInterpolator.interpolate(literal, local_ctxt, loc); 655 if(literal_val instanceof Stmt){ 656 return transformLiteralString(fl, type, (Stmt)literal_val, loc); 657 } 658 else{ 659 return MyUtil.value(fl.fromLiteral(literal_val.toString()), loc); 660 } 661 } 662 } 663 private Stmt transformLiteralString(final FromLiteral fl, 664 final Class type, 665 final Stmt stmt, final Location loc){ 666 return new Stmt(){ 667 public Class getType() { 668 return type; 669 } 670 public Object run(Dict frame, Runtime runtime) { 671 final String val = (String )convert(String .class, 672 stmt.run(frame, runtime), loc); 673 return fl.fromLiteral(val); 674 } 675 public Location getLocation() { 676 return loc; 677 } 678 public String toString() { 679 return stmt.toString(); 680 } 681 }; 682 } 683 private Stmt compileAttributeValue(Class expected_type, 684 Dict local_ctxt, String name){ 685 final String literal = getAttribute(name); 686 return compileLiteralValue(expected_type, local_ctxt, literal); 687 } 688 private Stmt getBooleanAttribute(Dict local_ctxt, String name, boolean def){ 689 final Stmt result = compileAttributeValue(boolean.class, 690 local_ctxt, name); 691 if(result==null){ 692 return MyUtil.value(Boolean.valueOf(def), getLocation()); 693 } 694 else return result; 695 } 696 private Stmt getSynchronizedAttribute(Dict local_ctxt){ 697 return getBooleanAttribute(local_ctxt, SYNCHRONIZED, false); 698 } 699 private Stmt getEagerInstantiationAttribute(Dict local_ctxt){ 700 Stmt result = compileLiteralValue(boolean.class, local_ctxt, 701 MyUtil.getEagerMode(tag)); 702 if(result==null){ 703 return MyUtil.value(Boolean.valueOf(default_eager_mode), getLocation()); 704 } 705 else return result; 706 } 707 private Stmt getTypeAttribute(Dict local_ctxt){ 708 final String literal = getAttribute(TYPE); 709 if(literal==null) return null; 710 final Location loc = getLocation(); 711 final FromLiteral fl = new FromLiteral(){ 712 public Object fromLiteral(String text){ 713 try{ 714 return MyUtil.getClass(getComponentClassLoader(), text); 715 } 716 catch(ClassNotFoundException e){ 717 throw new ConfigurationException( 718 getErrorMessage(tag.getName(), 719 "class "+text+" not found."), e, 720 loc); 721 } 722 } 723 }; 724 return compileLiteralString(Class .class, literal, fl, local_ctxt, loc); 725 742 } 743 private Stmt getAutowireAttribute(Dict local_ctxt, final ParameterBinder def){ 744 final String literal = getAttribute(AUTOWIRE); 745 final Location loc = getLocation(); 746 if(literal==null) return MyUtil.value(def, loc); 747 final FromLiteral fl = new FromLiteral(){ 748 public Object fromLiteral(String autowire){ 749 return MyUtil.getParamWiring(autowire, 750 getCustomWiringModes(), loc, def); 751 } 752 }; 753 return compileLiteralString(ParameterBinder.class, literal, fl, local_ctxt, loc); 754 779 } 780 private Stmt getSingletonAttribute(Dict local_ctxt, final SingletonMode def){ 781 final String literal = getAttribute(SINGLETON); 782 final Location loc = getLocation(); 783 if(literal==null) 784 return MyUtil.value(def, loc); 785 final FromLiteral fl = new FromLiteral(){ 786 public Object fromLiteral(String singleton){ 787 return MyUtil.getSingletonStrategy(singleton, loc, def); 788 } 789 }; 790 return compileLiteralString(ComponentDecorator.class, literal, fl, local_ctxt, loc); 791 815 } 816 817 818 819 820 private Stmt compileRefSymbol(String refname, Dict local_ctxt){ 821 return compileRef(refname.substring(1), local_ctxt); 822 } 823 private Stmt compileRef(String refname, Dict local_ctxt){ 824 if(!NutsUtils.isValidId(refname)){ 825 throw raise("invalid identifier: "+refname); 826 } 827 if(!local_ctxt.containsKey(refname)){ 828 throw raise("reference not recognized: "+refname); 829 } 830 return new Bound(refname, getLocation()); 831 } 832 833 private Stmt compileLiteral(String val, Dict local_ctxt){ 834 if(MyUtil.isRefName(val)){ 835 return compileRefSymbol(val, local_ctxt); 837 } 838 else{ 839 final Location loc = getLocation(); 840 return asStmt(StringInterpolator.interpolate(val, local_ctxt, loc), loc); 841 } 843 } 844 private Object compileRefLiteral(final Class type, String val, Dict local_ctxt){ 845 if(MyUtil.isRefName(val)){ 846 return compileRefSymbol(val, local_ctxt); 848 } 849 else if(isRefType(type)){ 850 return compileRef(val, local_ctxt); 853 } 854 else return StringInterpolator.interpolate(val, local_ctxt, getLocation()); 855 } 857 private Stmt compileLiteral(final Class type, String val, Dict local_ctxt){ 858 return asStmt(compileRefLiteral(type, val, local_ctxt), getLocation()); 859 864 } 865 public Entry[] compileMapEntries(String str, Dict local_ctxt){ 866 str = str.trim(); 867 final String [] entry_strs = NutsUtils.split(str, map_separator); 868 final ArrayList entries = new ArrayList (entry_strs.length); 869 for(int i=0; i<entry_strs.length; i++){ 870 entries.add(compileMapEntry(entry_strs[i], local_ctxt)); 871 } 872 final Entry[] result = new Entry[entries.size()]; 873 entries.toArray(result); 874 return result; 875 } 876 private Entry compileMapEntry(String str, Dict local_ctxt){ 877 final int delimit = str.indexOf('='); 878 if(delimit<0){ 879 throw raise("'=' is missing in a map entry."); 880 } 881 final String key_str = str.substring(0, delimit).trim(); 882 final String val_str = str.substring(delimit+1, str.length()).trim(); 883 final Stmt key = compileLiteral(key_str, local_ctxt); 884 final Stmt val = compileLiteral(val_str, local_ctxt); 885 return new Entry(key, val); 886 } 887 private Stmt[] compileParts(String [] parts, Class type, Dict local_ctxt){ 888 final Stmt[] result = new Stmt[parts.length]; 889 for(int i=0; i<result.length; i++){ 890 result[i] = compileLiteral(type, parts[i], local_ctxt); 891 } 892 return result; 893 } 894 private Stmt[] compileParts(String [] parts, Dict local_ctxt){ 895 final Stmt[] result = new Stmt[parts.length]; 896 for(int i=0; i<result.length; i++){ 897 result[i] = compileLiteral(parts[i], local_ctxt); 898 } 899 return result; 900 } 901 private Stmt compileListLiteral(final String val, Dict local_ctxt){ 902 final String [] parts = NutsUtils.split(val, list_separator); 903 final Location loc = getLocation(); 904 final Stmt[] stmts = compileParts(parts, local_ctxt); 905 return new LiteralStmt(ArrayList .class, val, loc){ 906 public Object run(Dict frame, Runtime runtime) { 907 final ListLiteral ll = new ListLiteral(stmts.length); 908 for(int i=0; i<stmts.length; i++){ 909 final Stmt stmt = stmts[i]; 910 ll.add(stmt.run(frame, runtime)); 911 } 912 return ll; 913 } 914 }; 915 } 916 private Stmt compileMapLiteral(final String val, Dict local_ctxt){ 917 final Entry[] entries = compileMapEntries(val, local_ctxt); 918 final Location loc = getLocation(); 919 return new LiteralStmt(ArrayList .class, val, loc){ 920 public Object run(Dict frame, Runtime runtime) { 921 final MapLiteral ml = new MapLiteral(entries.length); 922 for(int i=0; i<entries.length; i++){ 923 final Entry entry = entries[i]; 924 final Object key = ((Stmt)entry.getKey()).run(frame, runtime); 925 final Object val = ((Stmt)entry.getVal()).run(frame, runtime); 926 ml.build(key, val); 927 } 928 return ml; 929 } 930 }; 931 } 932 private Stmt compileCompound(final String val, final Class type, 933 Dict local_ctxt){ 934 final String [] parts = NutsUtils.split(val, list_separator); 935 final Location loc = getLocation(); 936 if(type.isArray()){ 937 final Class etype = type.getComponentType(); 938 final Stmt[] stmts = compileParts(parts, type, 939 local_ctxt); 940 return new LiteralStmt(type, val, loc){ 941 public Object run(Dict frame, Runtime runtime) { 942 final Object arr = Array.newInstance(etype, stmts.length); 943 for(int i=0; i<stmts.length; i++){ 944 final Stmt stmt = stmts[i]; 945 Array.set(arr, i, convert(etype, stmt.run(frame, runtime), stmt.getLocation())); 946 } 947 return arr; 948 } 949 }; 950 } 951 else if(isListType(type)){ 952 final Stmt[] stmts = compileParts(parts, local_ctxt); 953 return new LiteralStmt(type, val, loc){ 954 public Object run(Dict frame, Runtime runtime) { 955 try{ 956 final List list = jfun.yan.util.Utils 957 .createList(type, stmts.length); 958 for(int i=0; i<stmts.length; i++){ 959 list.add(stmts[i].run(frame, runtime)); 960 } 961 return list; 962 } 963 catch(Throwable e){ 964 throw raise(e); 965 } 966 } 967 }; 968 } 969 else if(Set .class.isAssignableFrom(type)){ 970 final Stmt[] stmts = compileParts(parts, local_ctxt); 971 return new LiteralStmt(type, val, loc){ 972 public Object run(Dict frame, Runtime runtime) { 973 try{ 974 final Set set = jfun.yan.util.Utils 975 .createSet(type, stmts.length); 976 for(int i=0; i<stmts.length; i++){ 977 final Object obj = stmts[i].run(frame, runtime); 978 if(set.contains(obj)){ 979 throw raise("duplicate set element:"+obj); 980 } 981 set.add(obj); 982 } 983 return set; 984 } 985 catch(Throwable e){ 986 throw raise(e); 987 } 988 } 989 }; 990 } 991 else{ 992 throw raise("either list or array is expected, "+Misc.getTypeName(type) 993 +" encountered"); 994 } 995 } 996 private Stmt compileMapLiteral(String val, Class type, Dict local_ctxt){ 997 final Entry[] entries = compileMapEntries(val, local_ctxt); 998 return new LiteralStmt(type, val, getLocation()){ 999 public Object run(Dict frame, Runtime runtime) { 1000 try{ 1001 final Map map = jfun.yan.util.Utils 1002 .createMap(type, entries.length); 1003 for(int i=0; i<entries.length; i++){ 1004 final Entry entry = entries[i]; 1005 final Object key = ((Stmt)entry.getKey()) 1006 .run(frame, runtime); 1007 if(map.containsKey(key)){ 1008 throw raise("duplicate map key:"+key); 1009 } 1010 final Object val = ((Stmt)entry.getVal()) 1011 .run(frame, runtime); 1012 map.put(key, val); 1013 } 1014 return map; 1015 } 1016 catch(Throwable e){ 1017 throw raise(e); 1018 } 1019 } 1020 }; 1021 } 1022 private boolean isMapLiteral(String val){ 1023 if(val.startsWith("{")){ 1024 if(!val.endsWith("}")){ 1026 throw raise("map literal has to be ended by a '}'"); 1027 } 1028 return true; 1029 } 1030 else 1031 return false; 1032 } 1033 private boolean isListLiteral(String val){ 1034 return (val.indexOf(',')>=0 && val.indexOf('$')>=0); 1035 } 1036 private Stmt attemptMapLiteral(String val, Dict local_ctxt){ 1037 val = val.trim(); 1038 if(isMapLiteral(val)){ 1039 return compileMapLiteral(val.substring(1, val.length()-1), local_ctxt); 1041 } 1042 else return null; 1043 } 1044 private Stmt attemptListLiteral(String val, Dict local_ctxt){ 1045 if(isListLiteral(val)){ 1046 return compileListLiteral(val, local_ctxt); 1047 } 1048 else return null; 1049 } 1050 private Stmt attemptMap(Class type, String val, Dict local_ctxt){ 1051 val = val.trim(); 1052 if(isMapLiteral(val)){ 1053 return compileMapLiteral(val.substring(1, val.length()-1), type, local_ctxt); 1054 } 1055 else return null; 1056 } 1057 private Stmt attemptCompound(Class type, String val, Dict local_ctxt){ 1058 if(isListLiteral(val)){ 1059 return compileCompound(val, type, local_ctxt); 1062 } 1063 else return null; 1064 } 1065 private SideEffect compileNutAttribute(String val, 1066 final PropertyDescriptor prop, Dict local_ctxt){ 1067 final Class type = prop.getPropertyType(); 1068 if(Map .class.isAssignableFrom(type)){ 1069 final Stmt stmt = attemptMap(type, val, local_ctxt); 1070 if(stmt!=null) 1071 return property_setter(prop, stmt); 1072 1073 } 1074 else if(isCompoundType(type)){ 1075 final Stmt stmt = attemptCompound(type, val, local_ctxt); 1076 if(stmt!=null) 1077 return property_setter(prop, stmt); 1078 } 1079 else if(Object .class.equals(type)){ 1080 Stmt stmt = attemptMapLiteral(val, local_ctxt); 1082 if(stmt==null) 1083 stmt = attemptListLiteral(val, local_ctxt); 1084 if(stmt!=null) 1085 return property_setter(prop, stmt); 1086 } 1087 return compileTerm(type, val, prop, local_ctxt); 1088 } 1089 private SideEffect compileTerm(final Class type, String val, final PropertyDescriptor prop, Dict local_ctxt) { 1090 final Object result = compileRefLiteral(type, val, local_ctxt); 1091 if(result instanceof Stmt){ 1092 return property_setter(prop, (Stmt)result); 1093 } 1094 else{ 1095 return literal_property_setter(prop, (String )result); 1096 } 1097 1102 } 1103 Object returnSubNut(NutDescriptor desc, Object nut, Object result){ 1104 if(result==null || !ReflectionUtil.isInstance(desc.getType(), result)){ 1105 return nut; 1106 } 1107 else return result; 1108 } 1109 private Stmt getCollectionNut(final String nutname, 1110 final NutDescriptor desc, final ArrayList mutations, 1111 final Stmt[] args, final boolean is_subnut){ 1112 final Class elem_type = desc.getSetterElementType(); 1113 final Location loc = getLocation(); 1114 return new Stmt(){ 1115 public String toString(){ 1116 return nutname; 1117 } 1118 public Object run(Dict frame, Runtime runtime){ 1119 final Object nut = createNut(nutname, 1120 desc, mutations, frame, runtime); 1121 try{ 1122 if(args.length!=0){ 1123 final Object arr = Array.newInstance(elem_type, args.length); 1124 for(int i=0; i<args.length; i++){ 1125 final Object elem = args[i].run(frame, runtime); 1126 final Object converted = convert(elem_type, elem, loc); 1127 try{ 1128 Array.set(arr, i, converted); 1129 } 1130 catch(IllegalArgumentException e){ 1131 raise("array element type mismatch: ["+i+"]"); 1132 } 1133 } 1134 desc.getSetter().invoke(nut, new Object []{arr}); 1135 } 1136 final Object result = desc.getEvaluator().eval(nut); 1137 return is_subnut?returnSubNut(desc, nut, result):result; 1139 } 1140 catch(Throwable e){ 1141 throw raise(e); 1142 } 1143 } 1144 public Class getType(){ 1145 return is_subnut?desc.getType():desc.getEvaluator().getType(); 1146 } 1147 public Location getLocation(){ 1148 return loc; 1149 } 1150 }; 1151 } 1152 1153 private void populateAdders(final String nutname, final NutDescriptor desc, 1154 final List nodes, final List mutations, final Dict ctxt){ 1155 final int sz = nodes.size(); 1156 for(int i=0; i<sz; i++){ 1157 final Node node = (Node)nodes.get(i); 1158 if(node instanceof CharacterData){ 1159 final CharacterData literal = (CharacterData)node; 1160 populateLiteralAdder(nutname, desc, literal, mutations); 1161 } 1162 else{ 1163 final Tag subtag = (Tag)node; 1164 populateSubnutAdder(i, desc, subtag, mutations, ctxt); 1165 } 1166 } 1167 } 1168 private void populateLiteralAdder(final String nutname, final NutDescriptor desc, 1169 CharacterData literal, List mutations){ 1170 final Location subloc = literal.getLocation(); 1171 1180 if(literal.getText().trim().length()==0){ 1181 return; 1183 } 1184 try{ 1185 1190 mutations.add(anonymous_adder_invoker(desc, 1191 MyUtil.value(literal.getText(), literal.getLocation()))); 1192 } 1193 catch(Throwable e){ 1194 raise(e, subloc); 1195 } 1196 } 1197 private void populateSubnutAdder(int seq, final NutDescriptor desc, 1198 Tag subtag, List mutations, Dict ctxt){ 1199 final String subname = subtag.getName(); 1200 NutDescriptor subdesc = desc.getSubDescriptor(subname); 1201 if(subdesc!=null){ 1202 final NutDescriptor customized_desc = 1203 (NutDescriptor)nut_descriptors.get(subname); 1204 if(customized_desc!=null){ 1205 if(subdesc.getType().isAssignableFrom(customized_desc.getType())){ 1206 subdesc = customized_desc; 1208 } 1209 } 1210 final Stmt sub = new TagCompiler(seq, ctxt, subtag, null, false, false) 1211 .compileNut(subname, subdesc, true); 1212 final Method adder = desc.getAdder(subname); 1213 mutations.add(dyn_method_invoker(adder, desc.getAdderType(subname), sub)); 1214 } 1215 else{ 1216 1222 final Stmt sub = compileLocalTag(seq, ctxt, subtag, false); 1223 mutations.add(anonymous_adder_invoker(desc, sub)); 1224 } 1225 } 1226 private Stmt getRegularNut(final String nutname, final NutDescriptor desc, 1227 final ArrayList mutations, final boolean is_subnut){ 1228 final Location loc = getLocation(); 1229 return new Stmt(){ 1230 public String toString(){ 1231 return nutname; 1232 } 1233 public Object run(Dict frame, Runtime runtime){ 1234 final Object nut = createNut(nutname, desc, mutations, 1235 frame, runtime); 1236 try{ 1237 final Object result = desc.getEvaluator().eval(nut); 1238 return is_subnut?returnSubNut(desc, nut, result):result; 1239 } 1240 catch(Throwable e){ 1241 throw raise(e); 1242 } 1243 } 1244 public Class getType(){ 1245 return is_subnut?desc.getType():desc.getEvaluator().getType(); 1246 } 1247 public Location getLocation(){ 1248 return loc; 1249 } 1250 }; 1251 } 1252 private Object createNut(final String nutname, 1253 NutDescriptor desc, ArrayList mutations, 1254 Dict ctxt, Runtime runtime){ 1255 try{ 1256 final Object nut = desc.createNut(); 1257 if(nut instanceof Nut){ 1258 final Nut r = (Nut)nut; 1259 r.initGloballyDefined(is_global); 1260 r.initSequenceNumber(ind); 1261 r.initTagLocation(getLocation()); 1262 r.initNutEnvironment(BodyCompiler.this); 1263 r.initTagName(nutname); 1264 1265 } 1266 final int sz = mutations.size(); 1267 for(int i=0; i<sz; i++){ 1268 ((SideEffect)mutations.get(i)).apply(nut, ctxt, runtime); 1269 } 1270 return nut; 1271 } 1272 catch(Throwable e){ 1273 throw raise(e); 1274 } 1275 } 1276 private boolean isSkippable(String name){ 1277 if(sys_attributes.contains(name)){ 1278 return true; 1279 } 1280 if(is_global && (EAGER_INSTANTIATED.equals(name)||EAGER_INSTANTIATED2.equals(name))){ 1281 return true; 1282 } 1283 else return false; 1284 } 1285 private Stmt compileNut(final String nutname, 1286 final NutDescriptor desc, final Dict local_ctxt, final List nodes, 1287 boolean is_subnut){ 1288 final Attributes attrs = tag.getAttributes(); 1289 final Map props = desc.getPropertyDescriptors(); 1290 final Location loc = getLocation(); 1291 final ArrayList mutations = new ArrayList (); 1293 for(int i=0; i<attrs.size(); i++){ 1294 final String name = NutsUtils.canonicalizeAttributeName(attrs.getKey(i)); 1295 final String val = attrs.getVal(i); 1296 final PropertyDescriptor prop = (PropertyDescriptor )props.get(name); 1297 if(prop == null){ 1298 if(!var_permitted && VAR.equals(name)){ 1299 throw raise(VAR + " not permitted in this context."); 1300 } 1301 if(isSkippable(name)){ 1302 continue; 1304 } 1305 else{ 1306 throw new ConfigurationException(name + " attribute not supported", loc); 1307 } 1308 } 1309 mutations.add(compileNutAttribute(val, prop, local_ctxt)); 1311 } 1312 if(desc.isCollectionNut()){ 1313 final Stmt[] stmts = new Stmt[nodes.size()]; 1315 final Class elem_type = desc.getSetterElementType(); 1316 for(int i=0; i<stmts.length; i++){ 1317 final Stmt stmt = compileNode(i, local_ctxt, 1318 (Node)nodes.get(i), false); 1319 checkElementType(elem_type, stmt); 1320 stmts[i] = stmt; 1321 } 1322 return getCollectionNut(nutname, desc, mutations, stmts, is_subnut); 1323 } 1324 else{ 1325 populateAdders(nutname, desc, nodes, mutations, local_ctxt); 1326 return getRegularNut(nutname, desc, mutations, is_subnut); 1327 } 1328 } 1329 private void assertNoCustomAttributes(){ 1330 if(!var_permitted){ 1331 if(tag.getAttribute(VAR)!=null){ 1332 raise(VAR + " not permitted in this context."); 1333 } 1334 } 1335 assertAttributes(sys_attributes); 1336 } 1337 1338 private Definition[] compileDefinitions(Dict ctxt, List subnodes, 1339 HashMap local_names){ 1340 final Definition[] stmts = new Definition[subnodes.size()]; 1341 for(int i=0; i<subnodes.size(); i++){ 1342 final Node node = (Node)(subnodes).get(i); 1343 final Location loc = node.getLocation(); 1344 if(node instanceof Tag){ 1345 Tag sub = (Tag)node; 1346 final String id = getIdAttribute(sub); 1347 final String var = getVarAttribute(sub); 1348 if(id!=null&&var!=null&&id.equals(var)){ 1349 throw new ConfigurationException("id and var cannot share the same value", 1350 loc); 1351 } 1352 checkDup(local_names, id, ID, loc); 1353 checkDup(local_names, var, VAR, loc); 1354 final Stmt stmt = compileLocalTag(i, ctxt, sub, true); 1355 1361 stmts[i] = new Definition(sub.getName(), id, var, stmt); 1362 if(id != null){ 1363 ctxt = declareName(ctxt, id, loc); 1364 } 1365 if(var != null) 1366 ctxt = declareName(ctxt, var, loc); 1367 } 1368 else{ 1369 throw new ConfigurationException(getName() + " only allow sub-elements that evaluates to Component", 1370 loc); 1371 } 1372 } 1373 return stmts; 1374 } 1375 private Stmt compileCallcc(Dict local_ctxt, List subnodes){ 1376 assertAttributes(callcc_attributes); 1377 final String exit = MyUtil.getMandatory(tag, EXIT); 1378 final Location loc = getLocation(); 1379 final Stmt body = compileSequential(declareName(local_ctxt, exit, loc), 1380 subnodes); 1381 return new Stmt(){ 1382 public Location getLocation() { 1383 return loc; 1384 } 1385 public Class getType() { 1386 return Component.class; 1387 } 1388 public Object run(Dict frame, Runtime runtime) { 1389 final Object id = new ReferentialId(exit); 1390 final NutsContinuation cont = new NutsContinuation(exit, loc, id); 1391 frame = frame.put(exit, cont); 1392 final Object r = body.run(frame, runtime); 1393 if(r instanceof Component){ 1394 final Component c = (Component)r; 1395 return new DelegatingComponent(c){ 1396 public Object create(Dependency dep){ 1397 try{ 1398 return super.create(dep); 1399 } 1400 catch(RuntimeException e){ 1401 final ContinuationEscapeException escape = 1402 MyUtil.getEscapeException(e); 1403 if(escape!=null && escape.getId()==id){ 1404 return escape.getResult(); 1405 } 1406 throw e; 1407 } 1408 } 1409 }; 1410 1424 } 1425 else return r; 1426 } 1427 }; 1428 } 1429 private Stmt compileSequence(Dict local_ctxt, List subnodes){ 1430 assertNoCustomAttributes(); 1432 return compileSequential(local_ctxt, subnodes); 1433 } 1434 private Stmt compileSequential(Dict local_ctxt, List subnodes){ 1435 final HashMap local_names = new HashMap (); 1436 final Definition[] stmt = compileDefinitions(local_ctxt, subnodes, local_names); 1437 return bindStatements(stmt, 0, stmt.length); 1438 } 1439 private Stmt compileBinder(Dict ctxt, List subnodes){ 1440 assertAttributes(bare_attributes); 1441 final String varname = getMandatoryVar(tag); 1442 final String id = getIdAttribute(tag); 1443 if(id!=null && id.equals(varname)){ 1444 throw raise(ID+" and "+VAR+" cannot share the same value"); 1445 } 1446 final HashMap local_names = new HashMap (); 1447 local_names.put(varname, varname); 1448 final Dict nctxt = ctxt; final Definition[] stmt = compileDefinitions(nctxt, subnodes, local_names); 1450 return compileBinder(varname, stmt, 0, stmt.length); 1451 } 1452 private Component seq(Component c1, Component c2){ 1453 if(c1==null) return c2; 1454 else return c1.seq(c2); 1455 } 1456 private Component evalDefinitions(final Definition[] defs, 1457 final int begin, final int end, Dict frame, Runtime runtime) { 1458 if(begin==end) 1459 return Components.value(null); 1460 Component cc = null; 1461 final int last = end - 1; 1462 for(int i=begin;i<end;i++){ 1463 final Definition def = defs[i]; 1464 final Object retval = evalStmt(def.stmt, runtime, frame); 1465 final boolean isComponent = retval instanceof Component; 1466 if(isComponent){ 1467 cc = seq(cc,(Component)retval); 1468 if(i==last) return cc; 1469 } 1470 else if(i==last){ 1471 return seq(cc, NutsUtils.asComponent(retval)); 1472 } 1473 1485 frame = nextFrame(def, frame, retval); 1486 final String vi = def.var; 1487 if(vi != null){ 1488 if(isComponent){ 1489 final Stmt binder = bindStatements(defs, i+1, end); 1490 return cc.bind(evalBinder(vi, 1491 binder, runtime, frame)); 1492 } 1493 else{ 1494 frame = frame.put(vi, retval); 1495 } 1496 } 1497 } 1498 return cc; 1499 } 1500 1501 private Stmt bindStatements(final Definition[] defs, 1502 final int begin, final int end){ 1503 final Location loc = this.tag.getLocation(); 1504 return new Stmt(){ 1505 public Location getLocation(){ 1506 return loc; 1507 } 1508 public Class getType(){ 1509 return Component.class; 1510 } 1511 public Object run(final Dict frame, Runtime runtime){ 1512 return evalDefinitions(defs, begin, end, frame, runtime); 1513 } 1514 public String toString(){ 1515 return StringUtils.listArray("[", ", ", "]", defs); 1516 } 1517 }; 1518 } 1519 private Stmt compileBinder(final String varname, 1520 final Definition[] stmt, 1521 final int begin, final int end){ 1522 final Location loc = this.tag.getLocation(); 1523 final Stmt body = bindStatements(stmt, begin, end); 1524 return new Stmt(){ 1525 public Location getLocation(){ 1526 return loc; 1527 } 1528 public Class getType(){ 1529 return Binder.class; 1530 } 1531 public Object run(final Dict frame, Runtime runtime){ 1532 return evalBinder(varname, body, runtime, frame); 1533 } 1534 public String toString(){ 1535 return body.toString(); 1536 } 1537 }; 1538 } 1539 } 1541 private static final class LocalScope{ 1542 private final Dict ctxt; 1543 private final Object [] keys; 1544 private final Stmt[] stmts; 1545 public String toString(){ 1546 return StringUtils.listArray("{",";","}",keys); 1547 } 1548 public Dict getScope() { 1549 return ctxt; 1550 } 1551 public Stmt[] getDefinitions() { 1552 return stmts; 1553 } 1554 public Object [] getKeys() { 1555 return keys; 1556 } 1557 public LocalScope(Object [] keys, Stmt[] stmts, Dict ctxt) { 1558 this.ctxt = ctxt; 1559 this.stmts = stmts; 1560 this.keys = keys; 1561 } 1562 1563 } 1564 static Stmt withScope(LocalScope scope, final Stmt stmt, final Location loc){ 1565 final Object [] keys = scope.getKeys(); 1566 final Stmt[] stmts = scope.getDefinitions(); 1567 return new Stmt(){ 1568 public String toString(){ 1569 return stmt.toString(); 1570 } 1571 public Object run(Dict frame, Runtime runtime){ 1572 return stmt.run(newFrame(keys, stmts, frame, runtime), runtime); 1573 } 1574 public Class getType(){ 1575 return stmt.getType(); 1576 } 1577 public Location getLocation(){ 1578 return loc; 1579 } 1580 }; 1581 } 1582 private static Dict newFrame(Object [] keys, Stmt[] stmts, 1583 Dict frame, final Runtime runtime){ 1584 final Thunk[] thunks = new Thunk[keys.length]; 1585 final Dict[] nframe = new Dict[1]; 1586 for(int i=0; i<keys.length; i++){ 1587 final Stmt stmt = stmts[i]; 1588 thunks[i] = new Thunk(keys[i], stmt.getLocation()){ 1589 Object evaluate(){ 1590 return stmt.run(nframe[0], runtime); 1591 } 1592 public Class getType(){ 1593 return stmt.getType(); 1594 } 1595 }; 1596 } 1597 nframe[0] = frame.puts(keys, thunks); 1598 return nframe[0]; 1599 } 1600 static Body evaluate(Object [] keys, Stmt[] stmts, 1601 Runtime runtime, 1602 Dict initial_frame){ 1603 final Dict frame = newFrame(keys, 1604 stmts, initial_frame, runtime); 1605 final Closure[] closures = new Closure[keys.length]; 1606 final Location[] locations = new Location[keys.length]; 1607 for(int i=0; i<keys.length; i++){ 1608 final Object key = keys[i]; 1609 closures[i] = (Closure)frame.get(key); 1611 locations[i] = stmts[i].getLocation(); 1612 } 1613 return new Body(keys, closures, locations); 1614 } 1615 1616 1617 private LocalScope compileLocalScope(final String tagname, Dict ctxt, List decs, 1618 IdChecker global, SingletonMode singleton_mode, boolean is_global){ 1619 final Object [] keys = new Object [decs.size()]; 1620 final Bound[] bounds = new Bound[keys.length]; 1621 final HashMap locals = new HashMap (keys.length); 1622 for(int i=0; i<keys.length; i++){ 1623 final Node node = (Node)decs.get(i); 1624 final Location loc = node.getLocation(); 1625 if(node instanceof Tag){ 1626 final Tag tag = (Tag)node; 1627 final String id = getIdAttribute(tag); 1628 if(id==null){ 1629 if(!is_global){ 1630 throw new ConfigurationException(ID+" is required.", 1631 loc); 1632 } 1633 else{ 1634 final Object aid = new AnonymousId(i); 1635 keys[i] = aid; 1636 bounds[i] = new Bound(aid, loc); 1637 } 1638 } 1639 else{ 1640 if(locals.containsKey(id)){ 1641 throw new ConfigurationException("duplicate id: "+id, loc); 1642 } 1643 if(reserves.contains(id)){ 1644 throw new ConfigurationException("id "+id+" is reserved.", loc); 1645 } 1646 if(global!=null) 1647 global.checkId(id, loc); 1648 keys[i] = id; 1649 bounds[i] = new Bound(id, loc); 1650 locals.put(id, id); 1651 } 1652 } 1653 else{ 1654 throw new ConfigurationException("only elements are allowed within "+tagname, 1655 loc); 1656 } 1657 } 1658 final Dict nctxt = ctxt.puts(keys, bounds); 1659 final Stmt[] stmts = new Stmt[keys.length]; 1660 for(int i=0; i<keys.length; i++){ 1661 final Tag tag = (Tag)decs.get(i); 1662 stmts[i] = compileTag(i, nctxt, tag, false, is_global, singleton_mode); 1663 } 1664 return new LocalScope(keys, stmts, nctxt); 1665 1666 } 1667 private LocalScope compileLocalScope(Dict ctxt, Tag localtag){ 1668 if(localtag.getAttributes().size()>0){ 1669 throw new ConfigurationException("attributes not allowed on local tag", 1670 localtag.getLocation()); 1671 } 1672 final List decs = localtag.getSubNodes(); 1673 return compileLocalScope(localtag.getName(), ctxt, decs, null, null, false); 1674 } 1675 1676 private static void checkDup(Map map, String key, String kind, Location loc){ 1677 if(key!=null && map.containsKey(key)){ 1678 throw new ConfigurationException("duplicate "+kind+": "+key, loc); 1679 } 1680 map.put(key, loc); 1681 } 1682 static final class Definition{ 1683 final Stmt stmt; 1684 final String var; 1685 final String id; 1686 final String tagname; 1687 Definition(String tagname, String id, String var, Stmt stmt) { 1688 this.tagname = tagname; 1689 this.stmt = stmt; 1690 this.var = var; 1691 this.id = id; 1692 } 1693 public String toString(){ 1694 return tagname; 1695 } 1696 } 1697 private static boolean maybeType(Class expected, Class actual){ 1698 if(actual == null) 1699 return true; 1700 return ReflectionUtil.isCompatible(expected, actual); 1701 } 1702 private Stmt compileNode( 1703 int ind, Dict ctxt, Node node, boolean var_permitted){ 1704 if(node instanceof CharacterData){ 1705 final CharacterData literal = (CharacterData)node; 1706 return MyUtil.value(literal.getText(), node.getLocation()); 1707 } 1708 else{ 1709 return compileLocalTag(ind, ctxt, (Tag)node, var_permitted); 1710 } 1711 } 1712 private Stmt compileTag(int ind, Dict ctxt, Tag tag, boolean var_permitted, boolean is_global, 1713 SingletonMode singleton_mode){ 1714 return new TagCompiler(ind, ctxt, tag, singleton_mode, var_permitted, is_global) 1715 .compile(); 1716 } 1717 private Stmt compileLocalTag(int ind, Dict local_ctxt, Tag tag, boolean var_permitted){ 1718 return compileTag(ind, local_ctxt, tag, var_permitted, false, null); 1719 } 1720 private void checkElementType(final Class expected, 1721 final Stmt stmt){ 1722 final Class type = stmt.getType(); 1723 final Location loc = stmt.getLocation(); 1724 if(maybeType(expected, type)){ 1725 return; 1726 } 1727 else if(String .class.equals(type)){ 1728 if(!isDeserializable(expected)){ 1729 throw new ConfigurationException("cannot convert string to " 1730 + Misc.getTypeName(expected), loc); 1731 } 1732 return; 1733 } 1734 else{ 1735 throw new ConfigurationException("cannot convert " + Misc.getTypeName(type) 1736 +" to " + Misc.getTypeName(expected), loc); 1737 } 1738 } 1739 static ConfigurationException raise(String msg, Throwable e, Location loc){ 1740 if(e instanceof ConfigurationException){ 1741 throw (ConfigurationException)e; 1742 } 1743 else if(e instanceof InvocationTargetException ){ 1744 throw raise(msg, ((InvocationTargetException )e).getTargetException(), loc); 1745 } 1746 throw new ConfigurationException(msg, e, loc); 1747 1748 } 1749 static ConfigurationException raise(Throwable e, Location loc){ 1750 if(e instanceof ConfigurationException){ 1751 throw (ConfigurationException)e; 1752 } 1753 else if(e instanceof InvocationTargetException ){ 1754 throw raise(((InvocationTargetException )e).getTargetException(), loc); 1755 } 1756 throw new ConfigurationException(e.getMessage(), e, loc); 1757 } 1758 1759 private SideEffect anonymous_adder_invoker( 1760 final NutDescriptor desc, 1761 final Stmt stmt){ 1762 return new SideEffect(){ 1763 public String toString(){ 1764 return "add"; 1765 } 1766 public void apply(Object obj, Dict frame, Runtime runtime){ 1767 try{ 1768 final Object v = stmt.run(frame, runtime); 1769 final Method mtd = desc.getAnonymousAdder(v); 1770 try{ 1771 mtd.invoke(obj, new Object []{v}); 1772 } 1773 catch(InvocationTargetException e){ 1774 throw new ConfigurationException(e.getTargetException(), stmt.getLocation()); 1775 } 1776 } 1777 catch(Throwable e){ 1778 throw raise(e, stmt.getLocation()); 1779 } 1780 } 1781 }; 1782 } 1783 private SideEffect dyn_method_invoker(final Method mtd, 1784 final Class param_type, 1785 final Stmt stmt){ 1786 return new SideEffect(){ 1787 public String toString(){ 1789 return mtd.toString(); 1790 } 1791 public void apply(Object obj, Dict frame, Runtime runtime){ 1792 try{ 1793 Object v = stmt.run(frame, runtime); 1794 1800 try{ 1801 mtd.invoke(obj, new Object []{ 1802 convert(param_type, v, stmt.getLocation())}); 1803 } 1804 catch(RuntimeException e){ 1805 throw new ConfigurationException("failed to invoke " + mtd.getName()+ 1806 "("+Misc.getTypeName(param_type)+") with argument of type " 1807 +(v==null?null:Misc.getTypeName(v.getClass())) 1808 , e, stmt.getLocation()); 1809 } 1810 } 1811 catch(Throwable e){ 1812 throw raise(e, stmt.getLocation()); 1813 } 1814 } 1815 }; 1816 } 1817 private static Object evalStmt(Stmt stmt, 1818 Runtime runtime, Dict frame){ 1819 final Object r = stmt.run(frame, runtime); 1820 return r; 1821 } 1822 private static Dict nextFrame(Definition c, Dict frame, Object cur){ 1823 final String id = c.id; 1824 if(id!=null){ 1825 frame = frame.put(id, cur); 1826 } 1827 return frame; 1828 } 1829 1837 private static boolean isCompoundType(Class type){ 1838 return type.isArray() || List .class.isAssignableFrom(type) 1839 || Set .class.isAssignableFrom(type) || Collection .class.equals(type); 1840 } 1841 private static boolean isListType(Class type){ 1842 return Collection .class.equals(type) || List .class.isAssignableFrom(type); 1843 } 1844 private static boolean isRefType(Class type){ 1845 return Component.class.equals(type) || Binder.class.isAssignableFrom(type) 1846 || NutsFunction.class.isAssignableFrom(type); 1847 } 1848 private Stmt cast(final Class target_type, final Stmt stmt){ 1849 return new Stmt(){ 1850 public Class getType() { 1851 return target_type; 1852 } 1853 public Object run(Dict frame, Runtime runtime) { 1854 return convert(target_type, stmt.run(frame, runtime), getLocation()); 1855 } 1856 public Location getLocation() { 1857 return stmt.getLocation(); 1858 } 1859 public String toString(){ 1860 return stmt.toString(); 1861 } 1862 }; 1863 } 1864 private static ComponentBinder evalBinder(final String varname, 1865 final Stmt stmt, final Runtime runtime, final Dict frame){ 1866 return new ComponentBinder(){ 1867 public String toString(){ 1868 return "\\"+varname+"->"+stmt; 1869 } 1870 public Creator bind(Object v){ 1871 Dict nframe = frame.put(varname, v); 1873 final Object retval = evalStmt(stmt, runtime, nframe); 1874 return NutsUtils.asComponent(retval); 1875 } 1876 1877 public Class bindType(Class type) { 1878 return stmt.getType(); 1879 } 1880 public Verifiable verify(Class type) { 1881 return Monad.verifyAs(stmt.getType()); 1882 } 1883 }; 1884 } 1885 AutoWiringMap getCustomWiringModes(){ 1886 return interpreter.getCustomWiringModes(); 1887 } 1888 public File getBaseDir() { 1889 return interpreter.getBaseDir(); 1890 } 1891 public ResourceLoader getResourceLoader(){ 1892 return interpreter.getResourceLoader(); 1893 } 1894 public ClassLoader getComponentClassLoader() { 1895 return interpreter.getClassloader(); 1896 } 1897 public ClassLoader getNutClassLoader(){ 1898 return interpreter.getClass().getClassLoader(); 1899 } 1900 public Object findService(Object key) { 1901 return interpreter.getServices().get(key); 1902 } 1903 public DefaultLifecycleManager getLifecycleManager(){ 1904 return interpreter.getLifecycleManager(); 1905 } 1906 public boolean isDeserializable(Class type){ 1907 return interpreter.isDeserializable(type); 1908 } 1909 public Object deserialize(Class type, String text) 1910 throws Throwable { 1911 return interpreter.deserialize(type, text); 1912 } 1913 public void registerDeserializer(Class type, Deserializer deserializer, 1914 boolean overriding, boolean mandatory){ 1915 interpreter.registerDeserializer(type, deserializer, 1916 overriding, mandatory); 1917 } 1918 private int seq_no = 0; 1919 public synchronized void registerEagerInstantiation(int ind, Object key, Component c){ 1920 interpreter.registerEagerInstantiation(new UID(module_id, ind, seq_no++, key), c); 1921 } 1922 public boolean isEagerlyInstantiating(){ 1923 return this.default_eager_mode; 1924 } 1925 public synchronized void registerDynamic(Object key, Object val, 1926 boolean overridable, boolean overriding, Location loc){ 1927 interpreter.registerDynamic(key, val, overridable, overriding, loc); 1928 } 1929 private interface FromLiteral{ 1930 Object fromLiteral(String literal); 1931 } 1932 private static Stmt asStmt(Object v, Location loc){ 1933 if(v instanceof Stmt){ 1934 return (Stmt)v; 1935 } 1936 else return MyUtil.value(v, loc); 1937 } 1938 1939} 1940 | Popular Tags |