1 4 package gnu.expr; 5 import gnu.mapping.*; 6 import gnu.bytecode.*; 7 import gnu.mapping.Location; 8 import gnu.lists.*; 9 import gnu.text.Lexer; 10 import gnu.text.SourceMessages; 11 import gnu.kawa.reflect.*; 12 import java.io.*; 13 import java.lang.reflect.InvocationTargetException ; 14 import gnu.kawa.lispexpr.ClassNamespace; 16 23 24 public abstract class Language 25 { 26 protected static final ThreadLocation current 27 = new ThreadLocation("language"); 28 29 public static Language getDefaultLanguage() 30 { return (Language) current.get(null); } 31 32 static { Environment.setGlobal(BuiltinEnvironment.getInstance()); } 33 34 public static void setDefaultLanguage(Language language) 35 { 36 current.set(language); 37 } 38 39 45 46 static String [][] languages = 47 { 48 { "scheme", ".scm", ".sc", "kawa.standard.Scheme" }, 49 { "krl", ".krl", "gnu.kawa.brl.BRL" }, 50 { "brl", ".brl", "gnu.kawa.brl.BRL" }, 51 { "emacs", "elisp", "emacs-lisp", ".el", "gnu.jemacs.lang.ELisp" }, 52 { "xquery", ".xquery", ".xq", ".xql", "gnu.xquery.lang.XQuery" }, 53 { "q2", ".q2", "gnu.q2.lang.Q2" }, 54 { "xslt", "xsl", ".xsl", "gnu.kawa.xslt.XSLT" }, 55 { "commonlisp", "common-lisp", "clisp", "lisp", 56 ".lisp", ".lsp", ".cl", 57 "gnu.commonlisp.lang.CommonLisp" } 58 }; 59 60 61 62 public static String [][] getLanguages() 63 { 64 return languages; 65 } 66 67 74 public static void registerLanguage(String [] langMapping) 75 { 76 String [][] newLangs = new String [languages.length + 1][]; 77 System.arraycopy(languages, 0, newLangs, 0, languages.length); 78 newLangs[newLangs.length - 1] = langMapping; 79 languages = newLangs; 80 } 81 82 85 public static Language detect (InputStream in) 86 throws IOException 87 { 88 if (! in.markSupported()) 89 return null; 90 StringBuffer sbuf = new StringBuffer (); 91 in.mark(200); 92 for (;;) 93 { 94 if (sbuf.length() >= 200) 95 break; 96 int c = in.read(); 97 if (c < 0 || c == '\n' || c == '\r') 98 break; 99 sbuf.append((char) c); 100 } 101 in.reset(); 102 return detect(sbuf.toString()); 103 } 104 105 108 public static Language detect (InPort port) 109 throws IOException 110 { 111 StringBuffer sbuf = new StringBuffer (); 112 port.mark(300); 113 port.readLine(sbuf, 'P'); 114 port.reset(); 115 return detect(sbuf.toString()); 116 } 117 118 122 public static Language detect (String line) 123 { 124 String str = line.trim(); 125 int k = str.indexOf("kawa:"); 127 if (k >= 0) 128 { 129 int i = k+5; 130 int j = i; 131 while (j < str.length() 132 && Character.isJavaIdentifierPart(str.charAt(j))) 133 j++; 134 if (j > i) 135 { 136 String w = str.substring(i, j); 137 Language lang = getInstance(w); 138 if (lang != null) 139 return lang; 140 } 141 } 142 if (str.indexOf("-*- scheme -*-") >= 0) 144 return getInstance("scheme"); 145 if (str.indexOf("-*- xquery -*-") >= 0) 146 return getInstance("xquery"); 147 if (str.indexOf("-*- emacs-lisp -*-") >= 0) 148 return getInstance("elisp"); 149 if (str.indexOf("-*- common-lisp -*-") >= 0 150 || str.indexOf("-*- lisp -*-") >= 0) 151 return getInstance("common-lisp"); 152 if ((str.charAt(0) == '(' && str.charAt(1) == ':') 154 || (str.length() >= 7 && str.substring(0, 7).equals("xquery "))) 155 return getInstance("xquery"); 156 if (str.charAt(0) == ';' && str.charAt(1) == ';') 157 return getInstance("scheme"); 158 return null; 159 } 160 161 public static Language getInstanceFromFilenameExtension(String filename) 162 { 163 int dot = filename.lastIndexOf('.'); 164 if (dot > 0) 165 { 166 Language lang = Language.getInstance(filename.substring(dot)); 167 if (lang != null) 168 return lang; 169 } 170 return null; 171 } 172 173 175 public static Language getInstance (String name) 176 { 177 int langCount = languages.length; 178 for (int i = 0; i < langCount; i++) 179 { 180 String [] names = languages[i]; 181 int nameCount = names.length - 1; 182 for (int j = nameCount; --j >= 0; ) 183 { 184 if (name == null || names[j].equalsIgnoreCase(name)) 185 { 186 Class langClass; 187 try 188 { 189 langClass = Class.forName(names[nameCount]); 190 } 191 catch (ClassNotFoundException ex) 192 { 193 break; 197 } 198 return getInstance(names[0], langClass); 199 } 200 } 201 } 202 return null; 203 } 204 205 protected Language () 206 { 207 gnu.lists.Convert.setInstance(KawaConvert.getInstance()); 208 } 209 210 public static Language getInstance (String langName, Class langClass) 211 { 212 try 213 { 214 java.lang.reflect.Method method; 215 Class [] args = { }; 216 try 217 { 218 String capitalizedName 219 = (Character.toTitleCase(langName.charAt(0)) 220 + langName.substring(1).toLowerCase()); 221 String methodName = "get" + capitalizedName + "Instance"; 222 method = langClass.getDeclaredMethod(methodName, args); 223 } 224 catch (Exception ex) 225 { 226 method 227 = langClass.getDeclaredMethod("getInstance", args); 228 } 229 return (Language) method.invoke(null, Values.noArgs); 230 } 231 catch (Exception ex) 232 { 233 langName = langClass.getName(); 234 Throwable th; 235 if (ex instanceof InvocationTargetException ) 236 th = ((InvocationTargetException ) ex).getTargetException(); 237 else 238 th = ex; 239 throw new WrappedException("getInstance for '" + langName + "' failed", 241 th); 242 } 243 } 244 245 246 public boolean isTrue(Object value) 247 { 248 return value != Boolean.FALSE; 249 } 250 251 public Object booleanObject(boolean b) 252 { 253 return b ? Boolean.TRUE : Boolean.FALSE; 254 } 255 256 257 public Object noValue() 258 { 259 return Values.empty; 260 } 261 262 264 public boolean hasSeparateFunctionNamespace() 265 { 266 return false; 267 } 268 269 270 protected Environment environ; 271 272 277 protected Environment userEnv; 278 279 280 public final Environment getEnvironment() 281 { 282 return userEnv != null ? userEnv : Environment.getCurrent(); 283 } 284 285 static int envCounter; 286 287 public final Environment getNewEnvironment () 288 { 289 return Environment.make("environment-"+(++envCounter), environ); 290 } 291 292 public Environment getLangEnvironment() { return environ; } 293 294 public NamedLocation lookupBuiltin (Symbol name, Object property, int hash) 295 { 296 return environ == null ? null : environ.lookup(name, property, hash); 297 } 298 299 300 public void define(String sym, Object p) 301 { 302 Symbol s = getSymbol(sym); 303 environ.define(s, null, p); 304 } 305 306 308 protected void defAliasStFld(String name, String cname, String fname) 309 { 310 StaticFieldLocation.define(environ, getSymbol(name), null, cname, fname); 311 } 312 313 319 protected void defProcStFld(String name, String cname, String fname) 320 { 321 Object property = (hasSeparateFunctionNamespace() ? EnvironmentKey.FUNCTION 322 : null); 323 Symbol sym = getSymbol(name); 324 StaticFieldLocation loc 325 = StaticFieldLocation.define(environ, sym, property, cname, fname); 326 loc.setProcedure(); 327 } 328 329 334 protected void defProcStFld(String name, String cname) 335 { 336 defProcStFld(name, cname, Compilation.mangleNameIfNeeded(name)); 337 } 338 339 340 public final void defineFunction(Named proc) 341 { 342 Object name = proc.getSymbol(); 343 Symbol sym = (name instanceof Symbol ? (Symbol) name 344 : getSymbol(name.toString())); 345 Object property = (hasSeparateFunctionNamespace() ? EnvironmentKey.FUNCTION 346 : null); 347 environ.define(sym, property, proc); 348 } 349 350 353 public void defineFunction(String name, Object proc) 354 { 355 Object property = (hasSeparateFunctionNamespace() ? EnvironmentKey.FUNCTION 356 : null); 357 environ.define(getSymbol(name), property, proc); 358 } 359 360 361 private void defineAll(Object object) 362 { 363 Class clas = object.getClass(); 364 java.lang.reflect.Field [] fields = clas.getFields(); 365 for (int i = fields.length; --i >= 0; ) 366 { 367 java.lang.reflect.Field field = fields[i]; 368 String name = field.getName(); 369 if (name.startsWith(Declaration.PRIVATE_PREFIX) 370 || name.endsWith("$instance")) 371 continue; 372 if ((field.getModifiers() & java.lang.reflect.Modifier.FINAL) != 0) 373 { 374 try 375 { 376 defineFromFieldValue(field, field.get(object)); 377 } 378 catch (Throwable ex) 379 { 380 throw new WrappedException("error accessing field "+field, ex); 381 } 382 } 383 else 384 { 385 System.err.println("INTERNAL ERROR in defineAll for " 386 + name + " in " + clas); 387 } 388 } 389 } 390 391 private void defineFromFieldValue(java.lang.reflect.Field fld, Object value) 392 throws Throwable 393 { 394 if (value instanceof Location) 395 { 396 Location loc = (Location) value; 397 Symbol sym = loc.getKeySymbol(); 398 if (sym != null) 399 { 400 environ.addLocation(sym, loc.getKeyProperty(), loc); 401 return; 402 } 403 } 404 else 405 { 406 Object vname; 407 if (value instanceof Named) 408 vname = ((Named) value).getSymbol(); 409 else 410 vname = null; 411 if (vname == null) 412 vname = Compilation.demangleName(fld.getName(), true).intern(); 413 Symbol symbol = vname instanceof Symbol ? (Symbol) vname 414 : environ.getSymbol(vname.toString()); 415 Object prop = getEnvPropertyFor(fld, value); 416 environ.define(symbol, prop, value); 417 } 418 } 419 420 public Object getEnvPropertyFor (java.lang.reflect.Field fld, Object value) 421 { 422 if (! hasSeparateFunctionNamespace()) 423 return null; 424 if (Compilation.typeProcedure.getReflectClass() 425 .isAssignableFrom(fld.getType())) 426 return EnvironmentKey.FUNCTION; 427 return null; 428 } 429 430 public Object getEnvPropertyFor (Declaration decl) 431 { 432 if (hasSeparateFunctionNamespace() && decl.isProcedureDecl()) 433 return EnvironmentKey.FUNCTION; 434 return null; 435 } 436 437 public void loadClass(String name) 438 throws java.lang.ClassNotFoundException 439 { 440 try 441 { 442 Class clas = Class.forName(name); 443 Object inst = clas.newInstance (); 444 defineAll(inst); 445 if (inst instanceof ModuleBody) 446 ((ModuleBody)inst).run(); 447 } 448 catch (java.lang.ClassNotFoundException ex) 449 { 450 throw ex; 451 } 452 catch (Exception ex) 453 { 454 throw new WrappedException("cannot load "+name, ex); 455 } 456 } 457 458 public Symbol getSymbol (String name) 459 { 460 return environ.getSymbol(name); 461 } 462 463 public Object lookup(String name) 464 { 465 return environ.get (name); 466 } 467 468 public AbstractFormat getFormat(boolean readable) 469 { 470 return null; 471 } 472 473 public Consumer getOutputConsumer(Writer out) 474 { 475 OutPort oport = out instanceof OutPort ? (OutPort) out 476 : new OutPort(out); 477 oport.objectFormat = getFormat(false); 478 return oport; 479 } 480 481 public String getName() 482 { 483 String name = getClass().getName(); 484 int dot = name.lastIndexOf('.'); 485 if (dot >= 0) 486 name = name.substring(dot+1); 487 return name; 488 } 489 490 public abstract Lexer getLexer(InPort inp, SourceMessages messages); 491 492 public Compilation getCompilation (Lexer lexer, SourceMessages messages) 493 { 494 return new Compilation(this, messages); 495 } 496 497 499 public static final int PARSE_IMMEDIATE = 1; 500 502 public static final int PARSE_ONE_LINE = 2; 503 506 public static final int PARSE_PROLOG = 4; 507 508 public static boolean requirePedantic; 509 510 518 public final Compilation parse(InPort port, 519 gnu.text.SourceMessages messages, 520 int options) 521 throws java.io.IOException , gnu.text.SyntaxException 522 { 523 return parse(getLexer(port, messages), options, null); 524 } 525 526 public final Compilation parse(InPort port, 527 gnu.text.SourceMessages messages, 528 ModuleInfo info) 529 throws java.io.IOException , gnu.text.SyntaxException 530 { 531 return parse(getLexer(port, messages), Language.PARSE_PROLOG, info); 532 } 533 534 public final Compilation parse(Lexer lexer, int options, ModuleInfo info) 535 throws java.io.IOException , gnu.text.SyntaxException 536 { 537 SourceMessages messages = lexer.getMessages(); 538 Compilation tr = getCompilation(lexer, messages); 539 if (requirePedantic) 540 tr.pedantic = true; 541 tr.immediate = (options & PARSE_IMMEDIATE) != 0; 542 if ((options & PARSE_PROLOG) != 0) 543 tr.setState(Compilation.PROLOG_PARSING); 544 tr.pushNewModule(lexer); 545 if (info != null) 546 info.setCompilation(tr); 547 if (! parse(tr, options)) 548 return null; 549 if (tr.getState() == Compilation.PROLOG_PARSING) 550 tr.setState(Compilation.PROLOG_PARSED); 551 return tr; 552 } 553 554 public abstract boolean parse (Compilation comp, int options) 555 throws java.io.IOException , gnu.text.SyntaxException; 556 557 560 public void resolve (Compilation comp) 561 { 562 } 563 564 public Type getTypeFor(Class clas) 565 { 566 return Type.make(clas); 567 } 568 569 public final Type getLangTypeFor (Type type) 570 { 571 if (! (type instanceof ObjectType) || ((ObjectType) type).isExisting()) 572 { 573 Class clas = type.getReflectClass(); 574 if (clas != null) 575 return getTypeFor(clas); 576 } 577 return type; 578 } 579 580 public static Type string2Type (String name) 581 { 582 Type t; 583 if (name.endsWith("[]")) 584 { 585 t = string2Type(name.substring(0, name.length()-2)); 586 if (t == null) 587 return null; 588 t = gnu.bytecode.ArrayType.make(t); 589 } 590 else if (gnu.bytecode.Type.isValidJavaTypeName(name)) 591 t = gnu.bytecode.Type.getType(name); 592 else 593 return null; 594 return t; 595 } 596 597 public Type getTypeFor (String name) 598 { 599 return string2Type(name); 600 } 601 602 public final Type getTypeFor (Object spec, boolean lenient) 603 { 604 if (spec instanceof Type) 605 return (Type) spec; 606 if (spec instanceof Class ) 607 return getTypeFor((Class ) spec); 608 if (lenient 609 && (spec instanceof FString 610 || spec instanceof String 611 || (spec instanceof Symbol && ((Symbol) spec).hasEmptyNamespace()) 612 || spec instanceof CharSeq)) 613 return getTypeFor(spec.toString()); 614 if (spec instanceof Namespace) 615 { 616 String uri = ((Namespace) spec).getName(); 617 if (uri != null && uri.startsWith("class:")) 618 return getLangTypeFor(string2Type(uri.substring(6))); 619 } 620 return null; 621 } 622 623 624 public final Type asType(Object spec) 625 { 626 Type type = getTypeFor(spec, true); 627 return type == null ? (Type) spec : type; 628 } 629 630 public final Type getTypeFor (Expression exp) 631 { 632 return getTypeFor(exp, true); 633 } 634 635 public Type getTypeFor (Expression exp, boolean lenient) 636 { 637 if (exp instanceof QuoteExp) 638 { 639 return getTypeFor(((QuoteExp) exp).getValue(), lenient); 640 } 641 else if (exp instanceof ReferenceExp) 642 { 643 ReferenceExp rexp = (ReferenceExp) exp; 644 Declaration decl = Declaration.followAliases(rexp.getBinding()); 645 String name = rexp.getName(); 646 if (decl != null) 647 { 648 name = decl.getName(); 649 exp = decl.getValue(); 650 if (decl.isAlias() 651 && exp instanceof QuoteExp) 652 { 653 Object val = ((QuoteExp) exp).getValue(); 654 if (val instanceof Location) 655 { 656 Location loc = (Location) val; 657 if (loc.isBound()) 658 return asType(loc.get()); 659 if (! (loc instanceof Named)) 660 return null; 661 name = ((Named) loc).getName(); 662 } 663 } 664 else if (! decl.getFlag(Declaration.IS_UNKNOWN)) 665 return getTypeFor(exp, lenient); 666 } 667 Object val = getEnvironment().get(name); 668 if (val instanceof Type) 669 return (Type) val; 670 if (val instanceof ClassNamespace) 671 return ((ClassNamespace) val).getClassType(); 672 int len = name.length(); 673 if (len > 2 && name.charAt(0) == '<' 674 && name.charAt(len-1) == '>') 675 return getTypeFor(name.substring(1, len-1)); 676 } 677 else if (exp instanceof ClassExp || exp instanceof ModuleExp) 678 { 679 return ((LambdaExp) exp).getType(); 680 } 681 return null; 682 } 683 684 public Declaration declFromField (ModuleExp mod, Object fvalue, Field fld) 685 { 686 String fname = fld.getName(); 687 Type ftype = fld.getType(); 688 boolean isAlias = ftype.isSubtype(Compilation.typeLocation); 689 Object fdname; 690 boolean isImportedInstance; 693 boolean externalAccess = false; 694 if ((isImportedInstance = fname.endsWith("$instance"))) 695 fdname = fname; 696 else if (fvalue instanceof Named) fdname = ((Named) fvalue).getSymbol(); 698 else 699 { 700 if (fname.startsWith(Declaration.PRIVATE_PREFIX)) 702 { 703 externalAccess = true; 704 fname = fname.substring(Declaration.PRIVATE_PREFIX.length()); 705 } 706 fdname = Compilation.demangleName(fname, true).intern(); 707 } 708 Type dtype = isAlias ? Type.pointer_type 709 : getTypeFor(ftype.getReflectClass()); 710 Declaration fdecl = mod.addDeclaration(fdname, dtype); 711 boolean isStatic = (fld.getModifiers() & Access.STATIC) != 0; 712 boolean isFinal = (fld.getModifiers() & Access.FINAL) != 0; 713 if (isAlias) 714 fdecl.setIndirectBinding(true); 715 else if (isFinal && ftype.isSubtype(Compilation.typeProcedure)) 716 fdecl.setProcedureDecl(true); 717 if (isStatic) 718 fdecl.setFlag(Declaration.STATIC_SPECIFIED); 719 fdecl.field = fld; 720 if (isFinal && ! isAlias) fdecl.setFlag(Declaration.IS_CONSTANT); 722 if (isImportedInstance) 723 fdecl.setFlag(Declaration.MODULE_REFERENCE); 724 fdecl.setSimple(false); 725 if (externalAccess) 726 fdecl.setFlag(Declaration.EXTERNAL_ACCESS|Declaration.PRIVATE); 727 return fdecl; 728 } 729 730 public static final int VALUE_NAMESPACE = 1<<0; 731 public static final int FUNCTION_NAMESPACE = 1<<1; 732 public static final int NAMESPACE_PREFIX_NAMESPACE = 1<<2; 733 734 742 public int getNamespaceOf(Declaration decl) 743 { 744 return VALUE_NAMESPACE; 745 } 746 747 749 public boolean hasNamespace (Declaration decl, int namespace) 750 { 751 return (getNamespaceOf(decl) & namespace) != 0; 752 } 753 754 public void emitPushBoolean(boolean value, CodeAttr code) 755 { 756 code.emitGetStatic(value ? Compilation.trueConstant 757 : Compilation.falseConstant); 758 } 759 760 763 public void emitCoerceToBoolean(CodeAttr code) 764 { 765 emitPushBoolean(false, code); 766 code.emitIfNEq(); 767 code.emitPushInt(1); 768 code.emitElse(); 769 code.emitPushInt(0); 770 code.emitFi(); 771 } 772 773 public Object coerceFromObject(Class clas, Object obj) 774 { 775 return getTypeFor(clas).coerceFromObject(obj); 776 } 777 778 public Object coerceToObject(Class clas, Object obj) 779 { 780 return getTypeFor(clas).coerceToObject(obj); 781 } 782 783 public Object coerceToObject(int val) 784 { 785 return gnu.math.IntNum.make(val); 786 } 787 788 public static synchronized void setDefaults (Language lang) 789 { 790 Language.setDefaultLanguage(lang); 791 current.setGlobal(lang); 792 if (Environment.getGlobal() == BuiltinEnvironment.getInstance()) 796 Environment.setGlobal(Environment.getCurrent()); 797 } 798 799 public Procedure getPrompter() 800 { 801 Object property = null; 802 if (hasSeparateFunctionNamespace()) 803 property = EnvironmentKey.FUNCTION; 804 Procedure prompter = (Procedure) getEnvironment() 805 .get(getSymbol("default-prompter"), property, null); 806 if (prompter != null) 807 return prompter; 808 else 809 return new SimplePrompter(); 810 } 811 812 813 public final Object eval (String string) throws Throwable 814 { 815 return eval(new CharArrayInPort(string)); 816 } 817 818 821 public final Object eval (Reader in) throws Throwable 822 { 823 return eval(in instanceof InPort ? (InPort) in : new InPort(in)); 824 } 825 826 827 public final Object eval (InPort port) throws Throwable 828 { 829 CallContext ctx = CallContext.getInstance(); 830 int oldIndex = ctx.startFromContext(); 831 try 832 { 833 eval(port, ctx); 834 return ctx.getFromContext(oldIndex); 835 } 836 catch (Throwable ex) 837 { 838 ctx.cleanupFromContext(oldIndex); 839 throw ex; 840 } 841 } 842 843 844 public final void eval (String string, Writer out) throws Throwable 845 { 846 eval(new CharArrayInPort(string), out); 847 } 848 849 852 public final void eval (String string, PrintConsumer out) throws Throwable 853 { 854 eval(string, getOutputConsumer(out)); 855 } 856 857 858 public final void eval (String string, Consumer out) throws Throwable 859 { 860 eval(new CharArrayInPort(string), out); 861 } 862 863 864 public final void eval (Reader in, Writer out) throws Throwable 865 { 866 eval(in, getOutputConsumer(out)); 867 } 868 869 870 public void eval (Reader in, Consumer out) throws Throwable 871 { 872 InPort port = in instanceof InPort ? (InPort) in : new InPort(in); 873 CallContext ctx = CallContext.getInstance(); 874 Consumer save = ctx.consumer; 875 try 876 { 877 ctx.consumer = out; 878 eval(port, ctx); 879 } 880 finally 881 { 882 ctx.consumer = save; 883 } 884 } 885 886 public void eval (InPort port, CallContext ctx) throws Throwable 887 { 888 SourceMessages messages = new SourceMessages(); 889 Language saveLang = getDefaultLanguage(); 890 setDefaultLanguage(this); 891 try 892 { 893 Compilation comp = parse(port, messages, PARSE_IMMEDIATE); 894 ModuleExp.evalModule(getEnvironment(), ctx, comp, null, null); 895 } 896 finally 897 { 898 setDefaultLanguage(saveLang); 899 } 900 if (messages.seenErrors()) 901 throw new RuntimeException ("invalid syntax in eval form:\n" 902 + messages.toString(20)); 903 } 904 905 static protected int env_counter = 0; 906 907 public void runAsApplication (String [] args) 908 { 909 setDefaults(this); 910 kawa.repl.main(args); 911 } 912 } 913 914 class SimplePrompter extends Procedure1 915 { 916 public String prefix = "["; 917 public String suffix = "] "; 918 919 public Object apply1 (Object arg) 920 { 921 if (arg instanceof InPort) 922 { 923 InPort port = (InPort) arg; 924 int line = port.getLineNumber() + 1; 925 if (line >= 0) 926 return prefix + line + suffix; 927 } 928 return suffix; 929 } 930 931 } 936 | Popular Tags |