diff --git a/.cvskeywords b/.cvskeywords index 014a1e06db..249011c861 100644 --- a/.cvskeywords +++ b/.cvskeywords @@ -1,45 +1,68 @@ -./factor/random.factor:! $Id: random.factor,v 1.3 2004/01/09 01:51:30 slava Exp $ -./factor/FactorExternalizable.java: * $Id: FactorExternalizable.java,v 1.3 2003/12/09 09:40:18 slava Exp $ -./factor/FactorJava.java: * $Id: FactorJava.java,v 1.12 2004/01/06 06:59:38 slava Exp $ -./factor/FactorDictionary.java: * $Id: FactorDictionary.java,v 1.12 2004/01/14 01:58:37 slava Exp $ -./factor/combinators.factor:! $Id: combinators.factor,v 1.17 2004/01/11 23:00:34 slava Exp $ -./factor/FactorDataStack.java: * $Id: FactorCallStack.java,v 1.1 2003/12/20 02:13:09 slava Exp $ -./factor/continuations.factor:! $Id: continuations.factor,v 1.8 2003/12/20 05:31:01 slava Exp $ -./factor/network.factor:! $Id: io.factor,v 1.2 2003/12/20 05:31:01 slava Exp $ -./factor/FactorLib.java: * $Id: FactorLib.java,v 1.10 2004/01/03 20:58:09 slava Exp $ -./factor/FactorRuntimeException.java: * $Id: FactorRuntimeException.java,v 1.3 2003/12/09 09:40:18 slava Exp $ -./factor/FactorRatio.java: * $Id: FactorRatio.java,v 1.1 2003/12/16 08:03:08 slava Exp $ -./factor/FactorCallStack.java: * $Id: FactorCallStack.java,v 1.1 2003/12/20 02:13:09 slava Exp $ -./factor/FactorStackException.java: * $Id: FactorStackException.java,v 1.3 2003/12/09 09:40:18 slava Exp $ -./factor/FactorUndefinedWordException.java: * $Id: FactorUndefinedWordException.java,v 1.1 2003/12/09 09:52:26 slava Exp $ -./factor/lists.factor:! $Id: lists.factor,v 1.10 2004/01/06 06:59:38 slava Exp $ -./factor/FactorCallFrame.java: * $Id: FactorCallFrame.java,v 1.3 2003/12/26 00:36:30 slava Exp $ -./factor/examples/httpd.factor:! $Id: httpd.factor,v 1.1 2004/01/15 03:00:18 slava Exp $ -./factor/FactorPrimitive.java: * $Id: FactorPrimitive.java,v 1.5 2004/01/11 23:00:34 slava Exp $ -./factor/FactorList.java: * $Id: FactorList.java,v 1.9 2004/01/03 20:58:09 slava Exp $ -./factor/FactorNamespace.java: * $Id: FactorNamespace.java,v 1.10 2004/01/08 04:14:14 slava Exp $ -./factor/PublicCloneable.java: * $Id: PublicCloneable.java,v 1.3 2003/12/09 09:40:18 slava Exp $ -./factor/examples.factor:! $Id: examples.factor,v 1.4 2004/01/12 02:07:31 slava Exp $ -./factor/FactorCompoundDefinition.java:* $Id: FactorCompoundDefinition.java,v 1.2 2004/01/14 01:58:37 slava Exp $ -./factor/FactorObject.java: * $Id: FactorObject.java,v 1.5 2003/12/19 21:40:00 slava Exp $ -./factor/FactorParser.java: * $Id: FactorParser.java,v 1.13 2004/01/10 23:24:30 slava Exp $ -./factor/FactorMath.java: * $Id: FactorMath.java,v 1.7 2003/12/26 00:36:30 slava Exp $ -./factor/parser.factor:! $Id: parser.factor,v 1.2 2003/12/20 04:30:06 slava Exp $ -./factor/FactorMissingDefinition.java: * $Id: FactorWordDefinition.java,v 1.10 2003/12/18 00:01:39 slava Exp $ -./factor/stream.factor:! $Id: stream.factor,v 1.1 2004/01/03 20:58:09 slava Exp $ -./factor/FactorReflectionForm.java:* $Id: FactorReflectionForm.java,v 1.1 2004/01/14 01:58:37 slava Exp $ -./factor/strings.factor:! $Id: strings.factor,v 1.4 2004/01/06 06:59:38 slava Exp $ -./factor/FactorInterpreter.java: * $Id: FactorInterpreter.java,v 1.32 2004/01/12 02:07:31 slava Exp $ -./factor/FactorDomainException.java: * $Id: FactorDomainException.java,v 1.3 2003/12/09 09:40:18 slava Exp $ -./factor/FactorWord.java: * $Id: FactorWord.java,v 1.10 2004/01/08 04:14:14 slava Exp $ -./factor/math.factor:! $Id: math.factor,v 1.11 2004/01/11 23:00:34 slava Exp $ -./factor/FactorWordDefinition.java: * $Id: FactorWordDefinition.java,v 1.17 2004/01/14 01:58:37 slava Exp $ -./factor/interpreter.factor:! $Id: interpreter.factor,v 1.14 2004/01/11 23:00:34 slava Exp $ -./factor/miscellaneous.factor:! $Id: miscellaneous.factor,v 1.5 2003/12/21 05:29:46 slava Exp $ -./factor/FactorArrayStack.java: * $Id: FactorArrayStack.java,v 1.3 2003/12/20 05:31:01 slava Exp $ -./factor/boot.factor:! $Id: boot.factor,v 1.12 2004/01/12 02:07:31 slava Exp $ -./factor/FactorParseException.java: * $Id: FactorParseException.java,v 1.3 2003/12/09 09:40:18 slava Exp $ -./factor/namespaces.factor:! $Id: namespaces.factor,v 1.4 2004/01/05 05:03:36 slava Exp $ -./factor/FactorException.java: * $Id: FactorException.java,v 1.3 2003/12/09 09:40:18 slava Exp $ -./factor/FactorShuffleDefinition.java: * $Id: FactorShuffleDefinition.java,v 1.5 2004/01/14 01:58:37 slava Exp $ -./factor/dictionary.factor:! $Id: dictionary.factor,v 1.6 2004/01/12 02:07:31 slava Exp $ +./factor/compiler/StackEffect.java: * $Id: StackEffect.java,v 1.6 2004/02/15 22:24:19 slava Exp $ +./factor/compiler/LocalAllocator.java: * $Id: LocalAllocator.java,v 1.9 2004/02/17 20:36:09 slava Exp $ +./factor/compiler/FactorCompilerException.java: * $Id: FactorCompilerException.java,v 1.1 2004/01/27 19:55:40 slava Exp $ +./factor/compiler/CompiledDefinition.java:* $Id: CompiledDefinition.java,v 1.4 2004/02/15 22:24:19 slava Exp $ +./factor/random.factor:! $Id: random.factor,v 1.6 2004/02/18 00:48:47 slava Exp $ +./factor/FactorExternalizable.java: * $Id: FactorExternalizable.java,v 1.1 2004/01/25 19:55:39 slava Exp $ +./factor/FactorJava.java: * $Id: FactorJava.java,v 1.7 2004/02/15 05:44:54 slava Exp $ +./factor/FactorDictionary.java: * $Id: FactorDictionary.java,v 1.8 2004/02/15 22:24:19 slava Exp $ +./factor/combinators.factor:! $Id: combinators.factor,v 1.4 2004/02/13 23:19:43 slava Exp $ +./factor/FactorDataStack.java: * $Id: FactorDataStack.java,v 1.3 2004/02/15 22:24:19 slava Exp $ +./factor/continuations.factor:! $Id: continuations.factor,v 1.1 2004/01/25 19:55:39 slava Exp $ +./factor/network.factor:! $Id: network.factor,v 1.2 2004/02/10 05:43:37 slava Exp $ +./factor/FactorLib.java: * $Id: FactorLib.java,v 1.4 2004/02/15 22:24:19 slava Exp $ +./factor/FactorRuntimeException.java: * $Id: FactorRuntimeException.java,v 1.1 2004/01/25 19:55:39 slava Exp $ +./factor/FactorRatio.java: * $Id: FactorRatio.java,v 1.1 2004/01/25 19:55:39 slava Exp $ +./factor/FactorCallStack.java: * $Id: FactorCallStack.java,v 1.2 2004/02/15 22:24:19 slava Exp $ +./factor/FactorStackException.java: * $Id: FactorStackException.java,v 1.1 2004/01/25 19:55:39 slava Exp $ +./factor/FactorUndefinedWordException.java: * $Id: FactorUndefinedWordException.java,v 1.1 2004/01/25 19:55:39 slava Exp $ +./factor/lists.factor:! $Id: lists.factor,v 1.7 2004/02/15 22:24:19 slava Exp $ +./factor/FactorCallFrame.java: * $Id: FactorCallFrame.java,v 1.3 2004/02/05 04:47:05 slava Exp $ +./factor/examples/httpd.factor:! $Id: httpd.factor,v 1.3 2004/02/13 23:19:43 slava Exp $ +./factor/FactorNamespace.java: * $Id: FactorNamespace.java,v 1.4 2004/02/05 04:47:05 slava Exp $ +./factor/PublicCloneable.java: * $Id: PublicCloneable.java,v 1.1 2004/01/25 19:55:39 slava Exp $ +./factor/examples.factor:! $Id: examples.factor,v 1.1 2004/01/25 19:55:39 slava Exp $ +./factor/Cons.java: * $Id: Cons.java,v 1.4 2004/02/11 03:49:45 slava Exp $ +./factor/FactorCompoundDefinition.java:* $Id: FactorCompoundDefinition.java,v 1.9 2004/02/15 22:24:19 slava Exp $ +./factor/FactorObject.java: * $Id: FactorObject.java,v 1.1 2004/01/25 19:55:39 slava Exp $ +./factor/FactorParser.java: * $Id: FactorParser.java,v 1.3 2004/01/26 03:16:54 slava Exp $ +./factor/FactorMath.java: * $Id: FactorMath.java,v 1.3 2004/02/17 20:36:09 slava Exp $ +./factor/parser.factor:! $Id: parser.factor,v 1.2 2004/02/10 05:43:37 slava Exp $ +./factor/FactorMissingDefinition.java: * $Id: FactorMissingDefinition.java,v 1.7 2004/02/15 22:24:19 slava Exp $ +./factor/stream.factor:! $Id: stream.factor,v 1.3 2004/02/10 05:43:37 slava Exp $ +./factor/strings.factor:! $Id: strings.factor,v 1.9 2004/02/18 00:48:47 slava Exp $ +./factor/FactorInterpreter.java: * $Id: FactorInterpreter.java,v 1.6 2004/02/17 20:36:09 slava Exp $ +./factor/FactorDomainException.java: * $Id: FactorDomainException.java,v 1.1 2004/01/25 19:55:39 slava Exp $ +./factor/FactorWord.java: * $Id: FactorWord.java,v 1.7 2004/02/15 05:44:54 slava Exp $ +./factor/math.factor:! $Id: math.factor,v 1.5 2004/02/17 20:36:09 slava Exp $ +./factor/FactorWordDefinition.java: * $Id: FactorWordDefinition.java,v 1.14 2004/02/15 22:24:19 slava Exp $ +./factor/primitives/CallstackSet.java: * $Id: CallstackSet.java,v 1.2 2004/02/15 22:24:19 slava Exp $ +./factor/primitives/JInvokeStatic.java: * $Id: JInvokeStatic.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/Unwind.java: * $Id: Unwind.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/JVarGetStatic.java: * $Id: JVarGetStatic.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/Unstack.java: * $Id: Unstack.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/JInvoke.java: * $Id: JInvoke.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/Get.java: * $Id: Get.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/Define.java: * $Id: Define.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/Clear.java: * $Id: Clear.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/Bind.java: * $Id: Bind.java,v 1.3 2004/02/17 20:36:09 slava Exp $ +./factor/primitives/Choice.java: * $Id: Choice.java,v 1.3 2004/02/17 03:49:46 slava Exp $ +./factor/primitives/JNew.java: * $Id: JNew.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/Call.java: * $Id: Call.java,v 1.2 2004/02/15 22:24:19 slava Exp $ +./factor/primitives/CallstackGet.java: * $Id: CallstackGet.java,v 1.2 2004/02/15 22:24:19 slava Exp $ +./factor/primitives/DatastackGet.java: * $Id: DatastackGet.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/JVarSet.java: * $Id: JVarSet.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/Set.java: * $Id: Set.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/Restack.java: * $Id: Restack.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/DatastackSet.java: * $Id: DatastackSet.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/JVarSetStatic.java: * $Id: JVarSetStatic.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/primitives/JVarGet.java: * $Id: JVarGet.java,v 1.2 2004/02/15 22:24:20 slava Exp $ +./factor/interpreter.factor:! $Id: interpreter.factor,v 1.6 2004/02/10 05:43:37 slava Exp $ +./factor/miscellaneous.factor:! $Id: miscellaneous.factor,v 1.5 2004/02/15 22:24:19 slava Exp $ +./factor/FactorArrayStack.java: * $Id: FactorArrayStack.java,v 1.2 2004/01/26 03:16:54 slava Exp $ +./factor/boot.factor:! $Id: boot.factor,v 1.5 2004/02/18 00:48:47 slava Exp $ +./factor/FactorParseException.java: * $Id: FactorParseException.java,v 1.1 2004/01/25 19:55:39 slava Exp $ +./factor/namespaces.factor:! $Id: namespaces.factor,v 1.4 2004/02/10 05:43:37 slava Exp $ +./factor/FactorException.java: * $Id: FactorException.java,v 1.1 2004/01/25 19:55:39 slava Exp $ +./factor/FactorShuffleDefinition.java: * $Id: FactorShuffleDefinition.java,v 1.12 2004/02/15 22:24:19 slava Exp $ +./factor/dictionary.factor:! $Id: dictionary.factor,v 1.8 2004/02/10 05:43:37 slava Exp $ diff --git a/factor/FactorList.java b/factor/Cons.java similarity index 61% rename from factor/FactorList.java rename to factor/Cons.java index 68ec146958..a1c0744f9c 100644 --- a/factor/FactorList.java +++ b/factor/Cons.java @@ -3,7 +3,7 @@ /* * $Id$ * - * Copyright (C) 2003 Slava Pestov. + * Copyright (C) 2003, 2004 Slava Pestov. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,20 +29,18 @@ package factor; -import java.util.LinkedList; -import java.util.List; /** * Used to build up linked lists. */ -public class FactorList implements PublicCloneable, FactorExternalizable +public class Cons implements PublicCloneable, FactorExternalizable { public static int COUNT; public Object car; public Object cdr; - //{{{ FactorList constructor - public FactorList(Object car, Object cdr) + //{{{ Cons constructor + public Cons(Object car, Object cdr) { this.car = car; this.cdr = cdr; @@ -63,9 +61,9 @@ public class FactorList implements PublicCloneable, FactorExternalizable } //}}} //{{{ next() method - public FactorList next() + public Cons next() { - return (FactorList)cdr; + return (Cons)cdr; } //}}} //{{{ get() method @@ -75,12 +73,12 @@ public class FactorList implements PublicCloneable, FactorExternalizable } //}}} //{{{ _get() method - public FactorList _get(int index) + public Cons _get(int index) { - FactorList iter = this; + Cons iter = this; while(index != 0) { - iter = (FactorList)iter.cdr; + iter = (Cons)iter.cdr; index--; } return iter; @@ -89,7 +87,7 @@ public class FactorList implements PublicCloneable, FactorExternalizable //{{{ contains() method public boolean contains(Object obj) { - FactorList iter = this; + Cons iter = this; while(iter != null) { if(FactorLib.objectsEqual(obj,iter.car)) @@ -99,100 +97,33 @@ public class FactorList implements PublicCloneable, FactorExternalizable return false; } //}}} - //{{{ set() method - /** - * Returns a new list where the item at the given index is changed. - */ - public FactorList set(int index, Object car, Object cdr) + //{{{ contains() method + public static boolean contains(Cons list, Object obj) { - if(index == 0) - return new FactorList(car,cdr); + if(list == null) + return false; else - { - return new FactorList(this.car, - this.next().set(index - 1,car,cdr)); - } - } //}}} - - //{{{ set() method - /** - * Returns a new list containing the first n elements of this list. - */ - public FactorList head(int n) - { - if(n == 0) - return null; - else if(cdr == null && n == 1) - return this; - else - { - FactorList head = next().head(n - 1); - if(head == cdr) - return this; - else - return new FactorList(car,head); - } + return list.contains(obj); } //}}} //{{{ length() method public int length() { int size = 0; - FactorList iter = this; + Cons iter = this; while(iter != null) { - iter = (FactorList)iter.cdr; + iter = (Cons)iter.cdr; size++; } return size; } //}}} - //{{{ append() method - public FactorList append(FactorList list) - { - if(list == null) - return this; - - FactorList returnValue = null; - FactorList end = null; - FactorList iter = this; - for(;;) - { - FactorList cons = new FactorList(iter.car,null); - if(end != null) - end.cdr = cons; - end = cons; - if(returnValue == null) - returnValue = cons; - if(iter.cdr == null) - { - end.cdr = list; - break; - } - else - iter = iter.next(); - } - return returnValue; - } //}}} - - //{{{ reverse() method - public FactorList reverse() - { - FactorList returnValue = null; - FactorList iter = this; - while(iter != null) - { - returnValue = new FactorList(iter.car,returnValue); - iter = iter.next(); - } - return returnValue; - } //}}} - //{{{ isProperList() method public boolean isProperList() { - return cdr == null || (cdr instanceof FactorList - && ((FactorList)cdr).isProperList()); + return cdr == null || (cdr instanceof Cons + && ((Cons)cdr).isProperList()); } //}}} //{{{ elementsToString() method @@ -203,17 +134,17 @@ public class FactorList implements PublicCloneable, FactorExternalizable public String elementsToString() { StringBuffer buf = new StringBuffer(); - FactorList iter = this; + Cons iter = this; while(iter != null) { if(iter.car == this) buf.append(""); else buf.append(FactorJava.factorTypeToString(iter.car)); - if(iter.cdr instanceof FactorList) + if(iter.cdr instanceof Cons) { buf.append(' '); - iter = (FactorList)iter.cdr; + iter = (Cons)iter.cdr; continue; } else if(iter.cdr == null) @@ -238,19 +169,6 @@ public class FactorList implements PublicCloneable, FactorExternalizable return "[ " + elementsToString() + " ]"; } //}}} - //{{{ toJavaList() method - public List toJavaList() - { - LinkedList returnValue = new LinkedList(); - FactorList iter = this; - while(iter != null) - { - returnValue.add(iter.car); - iter = (FactorList)iter.cdr; - } - return returnValue; - } //}}} - //{{{ toArray() method /** * Note that unlike Java list toArray(), the given array must already @@ -259,7 +177,7 @@ public class FactorList implements PublicCloneable, FactorExternalizable public Object[] toArray(Object[] returnValue) { int i = 0; - FactorList iter = this; + Cons iter = this; while(iter != null) { returnValue[i++] = iter.car; @@ -269,17 +187,17 @@ public class FactorList implements PublicCloneable, FactorExternalizable } //}}} //{{{ fromArray() method - public static FactorList fromArray(Object[] array) + public static Cons fromArray(Object[] array) { if(array == null || array.length == 0) return null; else { - FactorList first = new FactorList(array[0],null); - FactorList last = first; + Cons first = new Cons(array[0],null); + Cons last = first; for(int i = 1; i < array.length; i++) { - FactorList cons = new FactorList(array[i],null); + Cons cons = new Cons(array[i],null); last.cdr = cons; last = cons; } @@ -290,9 +208,9 @@ public class FactorList implements PublicCloneable, FactorExternalizable //{{{ equals() method public boolean equals(Object o) { - if(o instanceof FactorList) + if(o instanceof Cons) { - FactorList l = (FactorList)o; + Cons l = (Cons)o; return FactorLib.objectsEqual(car,l.car) && FactorLib.objectsEqual(cdr,l.cdr); } @@ -312,10 +230,10 @@ public class FactorList implements PublicCloneable, FactorExternalizable //{{{ clone() method public Object clone() { - if(cdr instanceof FactorList) - return new FactorList(car,((FactorList)cdr).clone()); + if(cdr instanceof Cons) + return new Cons(car,((Cons)cdr).clone()); else - return new FactorList(car,cdr); + return new Cons(car,cdr); } //}}} //{{{ deepClone() method @@ -326,13 +244,13 @@ public class FactorList implements PublicCloneable, FactorExternalizable ccar = ((PublicCloneable)car).clone(); else ccar = car; - if(cdr instanceof FactorList) + if(cdr instanceof Cons) { - return new FactorList(ccar,next().deepClone()); + return new Cons(ccar,next().deepClone()); } else if(cdr == null) { - return new FactorList(ccar,null); + return new Cons(ccar,null); } else { @@ -341,7 +259,7 @@ public class FactorList implements PublicCloneable, FactorExternalizable ccdr = ((PublicCloneable)cdr).clone(); else ccdr = cdr; - return new FactorList(ccar,ccdr); + return new Cons(ccar,ccdr); } } //}}} } diff --git a/factor/FactorArrayStack.java b/factor/FactorArrayStack.java index 393f0c9b3f..256ee40ea4 100644 --- a/factor/FactorArrayStack.java +++ b/factor/FactorArrayStack.java @@ -44,7 +44,7 @@ public abstract class FactorArrayStack implements FactorExternalizable } //}}} //{{{ FactorArrayStack constructor - public FactorArrayStack(FactorList list) + public FactorArrayStack(Cons list) { if(list != null) { @@ -126,12 +126,12 @@ public abstract class FactorArrayStack implements FactorExternalizable } //}}} //{{{ toList() method - public FactorList toList() + public Cons toList() { - FactorList first = null, last = null; + Cons first = null, last = null; for(int i = 0; i < top; i++) { - FactorList cons = new FactorList(stack[i],null); + Cons cons = new Cons(stack[i],null); if(first == null) first = cons; else diff --git a/factor/FactorCallFrame.java b/factor/FactorCallFrame.java index 5f80b4a58e..a9d5149565 100644 --- a/factor/FactorCallFrame.java +++ b/factor/FactorCallFrame.java @@ -44,13 +44,18 @@ public class FactorCallFrame implements PublicCloneable, FactorExternalizable /** * Next word to be evaluated. */ - public FactorList ip; + public Cons ip; /** * Collapsed tail calls? See call(). */ public boolean collapsed; + /** + * Compiled code? + */ + public boolean compiled; + //{{{ FactorCallFrame constructor public FactorCallFrame() { @@ -59,7 +64,7 @@ public class FactorCallFrame implements PublicCloneable, FactorExternalizable //{{{ FactorCallFrame constructor public FactorCallFrame(FactorWord word, FactorNamespace namespace, - FactorList ip) + Cons ip) { this.word = word; this.namespace = namespace; @@ -90,12 +95,17 @@ public class FactorCallFrame implements PublicCloneable, FactorExternalizable buf.append("at ").append(word); + if(compiled) + buf.append(" ( compiled )"); + else if(ip != null) + { + buf.append(" ( ip: ").append(ip.elementsToString()) + .append(" )"); + } + buf.append('\n').append(indent); - buf.append(" namespace: ").append(namespace) - .append('\n').append(indent); - - buf.append(" ip: ").append(ip); + buf.append(namespace); return buf.toString(); } //}}} diff --git a/factor/FactorCallStack.java b/factor/FactorCallStack.java index 565e788816..0b216806b1 100644 --- a/factor/FactorCallStack.java +++ b/factor/FactorCallStack.java @@ -60,6 +60,12 @@ public class FactorCallStack extends FactorArrayStack implements PublicCloneable //{{{ clone() method public Object clone() { - return new FactorCallStack(FactorLib.deepCloneArray(stack),top); + if(stack == null) + return new FactorCallStack(); + else + { + return new FactorCallStack( + FactorLib.deepCloneArray(stack),top); + } } //}}} } diff --git a/factor/FactorCompoundDefinition.java b/factor/FactorCompoundDefinition.java index 391f1769c7..94dd4a0cb3 100644 --- a/factor/FactorCompoundDefinition.java +++ b/factor/FactorCompoundDefinition.java @@ -29,289 +29,356 @@ package factor; +import factor.compiler.*; import java.lang.reflect.*; +import java.io.FileOutputStream; +import java.util.*; import org.objectweb.asm.*; +import org.objectweb.asm.util.*; /** * : name ... ; */ public class FactorCompoundDefinition extends FactorWordDefinition { - public FactorList definition; + private static int compileCount; - public FactorCompoundDefinition(FactorList definition) + public Cons definition; + + //{{{ FactorCompiledDefinition constructor + public FactorCompoundDefinition(FactorWord word, Cons definition) { + super(word); this.definition = definition; - } + } //}}} - public void eval(FactorWord word, FactorInterpreter interp) + //{{{ eval() method + public void eval(FactorInterpreter interp) throws Exception { interp.call(word,definition); - } + } //}}} - //{{{ canCompile() method - boolean canCompile() + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws Exception { - return true; + if(recursiveCheck.contains(this)) + return null; + + try + { + recursiveCheck.add(this); + + return StackEffect.getStackEffect(definition, + recursiveCheck,state); + } + finally + { + recursiveCheck.remove(this); + } + } //}}} + + //{{{ getSanitizedName() method + private String getSanitizedName(String name) + { + StringBuffer sanitizedName = new StringBuffer(); + for(int i = 0; i < name.length(); i++) + { + char ch = name.charAt(i); + if(!Character.isJavaIdentifierStart(ch)) + sanitizedName.append("_"); + else + sanitizedName.append(ch); + } + return "factor/compiler/gen/" + sanitizedName + + "_" + (compileCount++); } //}}} //{{{ compile() method + /** + * Compile the given word, returning a new word definition. + */ + FactorWordDefinition compile(FactorInterpreter interp, + Set recursiveCheck) throws Exception + { + StackEffect effect = getStackEffect( + recursiveCheck,new LocalAllocator()); + if(effect == null) + throw new FactorCompilerException("Cannot deduce stack effect of " + word); + if(effect.outD > 1) + throw new FactorCompilerException("Cannot compile word that returns more than 1 value"); + + /* StringBuffer buf = new StringBuffer(); + for(int i = 0; i < recursiveCheck.size(); i++) + { + buf.append(' '); + } + buf.append("Compiling ").append(word); + System.err.println(buf); */ + + String className = getSanitizedName(word.name); + + ClassWriter cw = new ClassWriter(false); + cw.visit(ACC_PUBLIC, className, + "factor/compiler/CompiledDefinition", null, null); + + compileConstructor(cw,className); + + CompileResult result = compileEval(interp,cw, + className,effect,recursiveCheck); + + compileToString(cw,effect); + + // Generate fields for storing literals and word references + result.allocator.generateFields(cw); + + // gets the bytecode of the class, and loads it dynamically + byte[] code = cw.toByteArray(); + + if(interp.compileDump) + { + FileOutputStream fos = new FileOutputStream(className + ".class"); + fos.write(code); + fos.close(); + } + + Class compiledWordClass = loader._defineClass( + className.replace('/','.'), + code, 0, code.length); + + result.allocator.setFields(compiledWordClass); + + Constructor constructor = compiledWordClass.getConstructor( + new Class[] { FactorWord.class, StackEffect.class }); + + FactorWordDefinition compiledWord = (FactorWordDefinition) + constructor.newInstance(new Object[] { word, effect }); + + // store disassembly for the 'asm' word. + compiledWord.getNamespace(interp).setVariable("asm", + result.asm); + + return compiledWord; + } //}}} + + //{{{ compileConstructor() method + private void compileConstructor(ClassVisitor cw, String className) + { + // creates a MethodWriter for the constructor + CodeVisitor mw = cw.visitMethod(ACC_PUBLIC, + "", + "(Lfactor/FactorWord;Lfactor/compiler/StackEffect;)V", + null, null); + // pushes the 'this' variable + mw.visitVarInsn(ALOAD, 0); + // pushes the word parameter + mw.visitVarInsn(ALOAD, 1); + // pushes the stack effect parameter + mw.visitVarInsn(ALOAD, 2); + // invokes the super class constructor + mw.visitMethodInsn(INVOKESPECIAL, + "factor/compiler/CompiledDefinition", "", + "(Lfactor/FactorWord;Lfactor/compiler/StackEffect;)V"); + mw.visitInsn(RETURN); + mw.visitMaxs(3, 3); + } //}}} + + //{{{ compileToString() method + private void compileToString(ClassVisitor cw, StackEffect effect) + { + // creates a MethodWriter for the 'toString' method + CodeVisitor mw = cw.visitMethod(ACC_PUBLIC, + "toString", "()Ljava/lang/String;", null, null); + mw.visitLdcInsn("( compiled: " + effect + " ) " + toString()); + mw.visitInsn(ARETURN); + mw.visitMaxs(1, 1); + } //}}} + + //{{{ compileEval() method + static class CompileResult + { + LocalAllocator allocator; + String asm; + + CompileResult(LocalAllocator allocator, String asm) + { + this.allocator = allocator; + this.asm = asm; + } + } + /** * Write the definition of the eval() method in the compiled word. * Local 0 -- this - * Local 1 -- word - * Local 2 -- interpreter + * Local 1 -- interpreter */ - boolean compile(FactorWord word, FactorInterpreter interp, - ClassWriter cw, CodeVisitor mw) - throws Exception + protected CompileResult compileEval(FactorInterpreter interp, + ClassWriter cw, String className, StackEffect effect, + Set recursiveCheck) throws Exception { - if(definition == null) - { + // creates a MethodWriter for the 'eval' method + CodeVisitor _mw = cw.visitMethod(ACC_PUBLIC, + "eval", "(Lfactor/FactorInterpreter;)V", + null, null); + + TraceCodeVisitor mw = new TraceCodeVisitor(_mw); + + // eval() method calls core + mw.visitVarInsn(ALOAD,1); + + compileDataStackToJVMStack(effect,mw); + + String signature = effect.getCorePrototype(); + + mw.visitMethodInsn(INVOKESTATIC, + className,"core",signature); + + compileJVMStackToDataStack(effect,mw); + + mw.visitInsn(RETURN); + mw.visitMaxs(Math.max(4,2 + effect.inD),4); + + String evalAsm = getDisassembly(mw); + + // generate core + _mw = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, + "core",signature,null,null); + + mw = new TraceCodeVisitor(_mw); + + LocalAllocator allocator = new LocalAllocator(interp, + className,1,effect.inD); + + int maxJVMStack = allocator.compile(definition,mw, + recursiveCheck); + + if(effect.outD == 0) mw.visitInsn(RETURN); - // Max stack and locals - mw.visitMaxs(1,1); - return true; - } - - FactorList fdef = compilePass1(interp,definition); - if(fdef.car instanceof FactorReflectionForm - && fdef.cdr == null) + else { - return ((FactorReflectionForm)fdef.car).compile( - word,interp,cw,mw); + allocator.pop(mw); + mw.visitInsn(ARETURN); + maxJVMStack = Math.max(maxJVMStack,1); } - /* else - System.err.println("WARNING: cannot compile reflection & more"); */ - return false; + mw.visitMaxs(maxJVMStack,allocator.maxLocals()); + + String coreAsm = getDisassembly(mw); + + return new CompileResult(allocator, + "eval(Lfactor/FactorInterpreter;)V:\n" + evalAsm + + "core" + signature + "\n" + coreAsm); } //}}} - //{{{ compilePass1() method + //{{{ getDisassembly() method + protected String getDisassembly(TraceCodeVisitor mw) + { + // Save the disassembly of the eval() method + StringBuffer buf = new StringBuffer(); + Iterator bytecodes = mw.getText().iterator(); + while(bytecodes.hasNext()) + { + buf.append(bytecodes.next()); + } + return buf.toString(); + } //}}} + + //{{{ compileDataStackToJVMStack() method + private void compileDataStackToJVMStack(StackEffect effect, + CodeVisitor mw) + { + if(effect.inD != 0) + { + mw.visitVarInsn(ALOAD,1); + mw.visitFieldInsn(GETFIELD, + "factor/FactorInterpreter", "datastack", + "Lfactor/FactorDataStack;"); + + // ensure the stack has enough elements + mw.visitInsn(DUP); + mw.visitIntInsn(BIPUSH,effect.inD); + mw.visitMethodInsn(INVOKEVIRTUAL, + "factor/FactorArrayStack", "ensurePop", + "(I)V"); + + // datastack.stack -> 2 + mw.visitInsn(DUP); + mw.visitFieldInsn(GETFIELD, + "factor/FactorArrayStack", "stack", + "[Ljava/lang/Object;"); + mw.visitVarInsn(ASTORE,2); + // datastack.top-args.length -> 3 + mw.visitInsn(DUP); + mw.visitFieldInsn(GETFIELD, + "factor/FactorArrayStack", "top", + "I"); + mw.visitIntInsn(BIPUSH,effect.inD); + mw.visitInsn(ISUB); + + // datastack.top -= args.length + mw.visitInsn(DUP_X1); + mw.visitFieldInsn(PUTFIELD, + "factor/FactorArrayStack", "top", + "I"); + + mw.visitVarInsn(ISTORE,3); + + for(int i = 0; i < effect.inD; i++) + { + mw.visitVarInsn(ALOAD,2); + mw.visitVarInsn(ILOAD,3); + mw.visitInsn(AALOAD); + if(i != effect.inD - 1) + mw.visitIincInsn(3,1); + } + } + } //}}} + + //{{{ compileJVMStackToDataStack() method + private void compileJVMStackToDataStack(StackEffect effect, + CodeVisitor mw) + { + if(effect.outD == 1) + { + // ( datastack ) + mw.visitVarInsn(ALOAD,1); + mw.visitFieldInsn(GETFIELD, + "factor/FactorInterpreter", "datastack", + "Lfactor/FactorDataStack;"); + + mw.visitInsn(SWAP); + mw.visitMethodInsn(INVOKEVIRTUAL, + "factor/FactorArrayStack", "push", + "(Ljava/lang/Object;)V"); + } + } //}}} + + //{{{ compileImmediate() method /** - * Turn reflection calls into ReflectionForm objects. + * Compile a call to this word. Returns maximum JVM stack use. */ - private FactorList compilePass1(FactorInterpreter interp, FactorList def) + public int compileImmediate(CodeVisitor mw, LocalAllocator allocator, + Set recursiveCheck) throws Exception { - if(!def.isProperList()) - return def; - - FactorList rdef = def.reverse(); - - FactorDictionary dict = interp.dict; - - // A list of words and Java reflection forms - FactorList fdef = null; - while(rdef != null) - { - Object car = rdef.car; - if(car == dict.jvarGet - || car == dict.jvarSet - || car == dict.jvarGetStatic - || car == dict.jvarSetStatic - || car == dict.jnew) - { - FactorList form = rdef; - rdef = form._get(3); - fdef = new FactorList(new FactorReflectionForm(form), - fdef); - } - else if(car == dict.jinvoke - || car == dict.jinvokeStatic) - { - FactorList form = rdef; - rdef = form._get(4); - fdef = new FactorList(new FactorReflectionForm(form), - fdef); - } - else if(car instanceof FactorList) - { - fdef = new FactorList(compilePass1( - interp,((FactorList)car)),fdef); - } - else - fdef = new FactorList(car,fdef); - - rdef = rdef.next(); - } - - return fdef; - } //}}} - - //{{{ precompile() method - void precompile(FactorWord newWord, FactorInterpreter interp) - throws Exception - { - FactorDictionary dict = interp.dict; - - if(definition != null) - { - FactorList before = definition; - FactorList fed = definition.reverse(); - precompile(interp,newWord,fed); - definition = fed.reverse(); - /* if(!def.equals(before)) - { - System.out.println("BEFORE: " + before); - System.out.println("AFTER: " + def); - } */ - } - } //}}} - - //{{{ precompile() method - /** - * Precompiling turns jconstructor, jfield and jmethod calls - * with all-literal arguments into inline - * Constructor/Field/Method literals. This improves performance. - */ - private void precompile(FactorInterpreter interp, - FactorWord newWord, FactorList list) - throws Exception - { - if(interp.compile) - return; - - FactorDictionary dict = interp.dict; - - while(list != null) - { - Object o = list.car; - if(o instanceof FactorWord) - { - FactorWord word = (FactorWord)o; - if(word.def != FactorMissingDefinition.INSTANCE) - { - word.def.references++; - } - else - { - /*System.err.println( - "WARNING: " - + newWord - + " references " - + o - + " before its defined");*/ - } - - if(o == dict.jconstructor) - { - jconstructorPrecompile( - interp,list); - } - else if(o == dict.jmethod) - { - jmethodPrecompile( - interp,list); - } - else if(o == dict.jfield) - { - jfieldPrecompile( - interp,list); - } - } - else if(o instanceof FactorList) - { - if(((FactorList)o).isProperList()) - { - FactorList l = (FactorList)o; - FactorList _l = l.reverse(); - precompile(interp,newWord,_l); - list.car = _l.reverse(); - } - } - list = list.next(); - } - } //}}} - - //{{{ jconstructorPrecompile() method - private void jconstructorPrecompile( - FactorInterpreter interp, FactorList list) - throws Exception - { - FactorList cdr = list.next(); - if(cdr == null) - return; - if(!(cdr.car instanceof String)) - return; - String clazz = (String)cdr.car; - - FactorList cddr = cdr.next(); - if(cddr == null) - return; - if(!(cddr.car instanceof FactorList)) - return; - FactorList args = (FactorList)cddr.car; - - Constructor c = FactorJava.jconstructor(clazz,args); - - list.car = c; - list.cdr = cddr.next(); - } //}}} - - //{{{ jfieldPrecompile() method - private void jfieldPrecompile( - FactorInterpreter interp, FactorList list) - throws Exception - { - FactorList cdr = list.next(); - if(cdr == null) - return; - if(!(cdr.car instanceof String)) - return; - String field = (String)cdr.car; - - FactorList cddr = cdr.next(); - if(cddr == null) - return; - if(!(cddr.car instanceof String)) - return; - String clazz = (String)cddr.car; - - Field f = FactorJava.jfield(field,clazz); - - list.car = f; - list.cdr = cddr.next(); - } //}}} - - //{{{ jmethodPrecompile() method - /** - * Check if this jmethod has all-literal arguments, and if so, - * inline the result. - */ - private void jmethodPrecompile( - FactorInterpreter interp, FactorList list) - throws Exception - { - FactorList cdr = list.next(); - if(cdr == null) - return; - if(!(cdr.car instanceof String)) - return; - String method = (String)cdr.car; - - FactorList cddr = cdr.next(); - if(cddr == null) - return; - if(!(cddr.car instanceof String)) - return; - String clazz = (String)cddr.car; - - FactorList cdddr = cddr.next(); - if(cdddr == null) - return; - if(!(cdddr.car instanceof FactorList)) - return; - FactorList args = (FactorList)cdddr.car; - - Method m = FactorJava.jmethod(method,clazz,args); - - list.car = m; - list.cdr = cdddr.next(); + return allocator.compile(definition,mw,recursiveCheck); } //}}} + //{{{ toString() method public String toString() { return definition.elementsToString(); - } + } //}}} + + private static SimpleClassLoader loader = new SimpleClassLoader(); + + //{{{ SimpleClassLoader class + static class SimpleClassLoader extends ClassLoader + { + public Class _defineClass(String name, + byte[] code, int off, int len) + { + return defineClass(name,code,off,len); + } + } //}}} } diff --git a/factor/FactorDataStack.java b/factor/FactorDataStack.java index 87da5c185a..513313db05 100644 --- a/factor/FactorDataStack.java +++ b/factor/FactorDataStack.java @@ -41,7 +41,7 @@ public class FactorDataStack extends FactorArrayStack implements PublicCloneable } //}}} //{{{ FactorDataStack constructor - public FactorDataStack(FactorList list) + public FactorDataStack(Cons list) { super(list); } //}}} @@ -66,6 +66,12 @@ public class FactorDataStack extends FactorArrayStack implements PublicCloneable //{{{ clone() method public Object clone() { - return new FactorDataStack(FactorLib.cloneArray(stack),top); + if(stack == null) + return new FactorDataStack(); + else + { + return new FactorDataStack( + FactorLib.cloneArray(stack),top); + } } //}}} } diff --git a/factor/FactorDictionary.java b/factor/FactorDictionary.java index 9968c58309..0cdd0764c6 100644 --- a/factor/FactorDictionary.java +++ b/factor/FactorDictionary.java @@ -3,7 +3,7 @@ /* * $Id$ * - * Copyright (C) 2003 Slava Pestov. + * Copyright (C) 2003, 2004 Slava Pestov. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,23 +29,36 @@ package factor; +import factor.primitives.*; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; public class FactorDictionary { - // these are defined here for use by the precompiler - FactorWord jconstructor; + public FactorWord last; + + FactorWord datastackGet; + FactorWord datastackSet; + FactorWord clear; + FactorWord callstackGet; + FactorWord callstackSet; + FactorWord restack; + FactorWord unstack; + FactorWord unwind; FactorWord jnew; - FactorWord jfield; FactorWord jvarGet; FactorWord jvarSet; FactorWord jvarGetStatic; FactorWord jvarSetStatic; - FactorWord jmethod; FactorWord jinvoke; FactorWord jinvokeStatic; + FactorWord get; + FactorWord set; + FactorWord define; + FactorWord call; + FactorWord bind; + FactorWord choice; private Map intern; @@ -55,50 +68,65 @@ public class FactorDictionary intern = new TreeMap(); // data stack primitives - intern("datastack$").def = new FactorPrimitive.P_datastackGet(); - intern("datastack@").def = new FactorPrimitive.P_datastackSet(); - intern("clear").def = new FactorPrimitive.P_clear(); + datastackGet = intern("datastack$"); + datastackGet.def = new DatastackGet( + datastackGet); + datastackSet = intern("datastack@"); + datastackSet.def = new DatastackSet( + datastackSet); + clear = intern("clear"); + clear.def = new Clear(clear); // call stack primitives - intern("callstack$").def = new FactorPrimitive.P_callstackGet(); - intern("callstack@").def = new FactorPrimitive.P_callstackSet(); - intern("restack").def = new FactorPrimitive.P_restack(); - intern("unstack").def = new FactorPrimitive.P_unstack(); - intern("unwind").def = new FactorPrimitive.P_unwind(); + callstackGet = intern("callstack$"); + callstackGet.def = new CallstackGet( + callstackGet); + callstackSet = intern("callstack@"); + callstackSet.def = new CallstackSet( + callstackSet); + restack = intern("restack"); + restack.def = new Restack(restack); + unstack = intern("unstack"); + unstack.def = new Unstack(unstack); + unwind = intern("unwind"); + unwind.def = new Unwind(unwind); // reflection primitives - jconstructor = intern("jconstructor"); - jconstructor.def = new FactorPrimitive.P_jconstructor(); - jfield = intern("jfield"); - jfield.def = new FactorPrimitive.P_jfield(); jinvoke = intern("jinvoke"); - jinvoke.def = new FactorPrimitive.P_jinvoke(); - jinvokeStatic = intern("jinvokeStatic"); - jinvokeStatic.def = new FactorPrimitive.P_jinvokeStatic(); - jmethod = intern("jmethod"); - jmethod.def = new FactorPrimitive.P_jmethod(); + jinvoke.def = new JInvoke(jinvoke); + jinvokeStatic = intern("jinvoke-static"); + jinvokeStatic.def = new JInvokeStatic( + jinvokeStatic); jnew = intern("jnew"); - jnew.def = new FactorPrimitive.P_jnew(); + jnew.def = new JNew(jnew); jvarGet = intern("jvar$"); - jvarGet.def = new FactorPrimitive.P_jvarGet(); - jvarGetStatic = intern("jvarStatic$"); - jvarGetStatic.def = new FactorPrimitive.P_jvarGetStatic(); + jvarGet.def = new JVarGet(jvarGet); + jvarGetStatic = intern("jvar-static$"); + jvarGetStatic.def = new JVarGetStatic( + jvarGetStatic); jvarSet = intern("jvar@"); - jvarSet.def = new FactorPrimitive.P_jvarSet(); - jvarSetStatic = intern("jvarStatic@"); - jvarSetStatic.def = new FactorPrimitive.P_jvarSetStatic(); + jvarSet.def = new JVarSet(jvarSet); + jvarSetStatic = intern("jvar-static@"); + jvarSetStatic.def = new JVarSetStatic( + jvarSetStatic); // namespaces - intern("$").def = new FactorPrimitive.P_get(); - intern("@").def = new FactorPrimitive.P_set(); - intern("s@").def = new FactorPrimitive.P_swap_set(); + get = intern("$"); + get.def = new Get(get); + set = intern("@"); + set.def = new Set(set); // definition - intern("define").def = new FactorPrimitive.P_define(); + define = intern("define"); + define.def = new Define(define); // combinators - intern("call").def = new FactorPrimitive.P_call(); - intern("bind").def = new FactorPrimitive.P_bind(); + call = intern("call"); + call.def = new Call(call); + bind = intern("bind"); + bind.def = new Bind(bind); + choice = intern("?"); + choice.def = new Choice(choice); } //}}} //{{{ intern() method @@ -114,17 +142,17 @@ public class FactorDictionary } //}}} //{{{ toWordList() method - public FactorList toWordList() + public Cons toWordList() { - FactorList first = null; - FactorList last = null; + Cons first = null; + Cons last = null; Iterator iter = intern.values().iterator(); while(iter.hasNext()) { FactorWord word = (FactorWord)iter.next(); - if(word.def != FactorMissingDefinition.INSTANCE) + if(!(word.def instanceof FactorMissingDefinition)) { - FactorList cons = new FactorList(word,null); + Cons cons = new Cons(word,null); if(first == null) first = cons; else diff --git a/factor/FactorInterpreter.java b/factor/FactorInterpreter.java index 20bf101faf..16764a1b4c 100644 --- a/factor/FactorInterpreter.java +++ b/factor/FactorInterpreter.java @@ -33,15 +33,15 @@ import java.io.*; public class FactorInterpreter { - /** - * boot.factor checks this, if its true, an interpreter is run on - * standard input. - */ - public boolean interactive = false; + // command line arguments are stored here. + public Cons args; + // boot.factor sets these. + public boolean interactive = true; public boolean trace = false; public boolean errorFlag = false; public boolean compile = true; + public boolean compileDump = false; public FactorCallFrame callframe; public FactorCallStack callstack = new FactorCallStack(); @@ -57,21 +57,9 @@ public class FactorInterpreter { FactorInterpreter interp = new FactorInterpreter(); - boolean virgin = false; + interp.init(args,null); - for(int i = 0; i < args.length; i++) - { - if(args[i].equals("-trace")) - interp.trace = true; - else if(args[i].equals("-virgin")) - virgin = true; - else if(args[i].equals("-interp")) - interp.compile = false; - } - - interp.interactive = true; - interp.init(null,!virgin); - if(virgin) + /* if(virgin) { System.out.println("Mini-interpreter"); BufferedReader in = new BufferedReader( @@ -89,7 +77,7 @@ public class FactorInterpreter FactorParser parser = new FactorParser( "",new StringReader(line), interp.dict); - FactorList parsed = parser.parse(); + Cons parsed = parser.parse(); interp.call(parsed); interp.run(); System.out.println(interp.datastack); @@ -98,21 +86,22 @@ public class FactorInterpreter else { interp.run(); - } + } */ System.exit(0); } //}}} //{{{ init() method - public void init(Object root, boolean bootstrap) throws Exception + public void init(String[] args, Object root) throws Exception { + this.args = Cons.fromArray(args); + callstack.top = 0; datastack.top = 0; dict.init(); initNamespace(root); topLevel(); - if(bootstrap) - runBootstrap(); + runBootstrap(); } //}}} //{{{ initNamespace() method @@ -122,8 +111,9 @@ public class FactorInterpreter global.setVariable("interpreter",this); - String[] boundFields = { "compile", "interactive", "trace", - "dict", "errorFlag" }; + String[] boundFields = { "compile", "compileDump", + "interactive", "trace", + "dict", "errorFlag", "args" }; for(int i = 0; i < boundFields.length; i++) { global.setVariable(boundFields[i], @@ -160,7 +150,7 @@ public class FactorInterpreter if(callframe == null) break; - FactorList ip = callframe.ip; + Cons ip = callframe.ip; if(ip == null) { @@ -213,6 +203,8 @@ public class FactorInterpreter System.err.println("Factor callstack:"); System.err.println(callstack); + topLevel(); + return true; } else @@ -231,6 +223,8 @@ public class FactorInterpreter System.err.println("Factor callstack:"); System.err.println(callstack); + topLevel(); + return true; } } @@ -240,7 +234,7 @@ public class FactorInterpreter /** * Pushes the given list of code onto the callstack. */ - public final void call(FactorList code) + public final void call(Cons code) { call(dict.intern("call"),code); } //}}} @@ -249,7 +243,7 @@ public class FactorInterpreter /** * Pushes the given list of code onto the callstack. */ - public final void call(FactorWord word, FactorList code) + public final void call(FactorWord word, Cons code) { if(callframe == null) call(word,global,code); @@ -261,7 +255,7 @@ public class FactorInterpreter /** * Pushes the given list of code onto the callstack. */ - public final void call(FactorWord word, FactorNamespace namespace, FactorList code) + public final void call(FactorWord word, FactorNamespace namespace, Cons code) { FactorCallFrame newcf; @@ -321,17 +315,15 @@ public class FactorInterpreter if(obj instanceof FactorWord) { - FactorWord w = (FactorWord)obj; - try { - w.def.eval(w,this); + ((FactorWord)obj).def.eval(this); } catch(Exception e) { callstack.push(callframe); callframe = new FactorCallFrame( - w, + (FactorWord)obj, callframe.namespace, null); throw e; diff --git a/factor/FactorJava.java b/factor/FactorJava.java index 0c5802eb04..0ae6178563 100644 --- a/factor/FactorJava.java +++ b/factor/FactorJava.java @@ -29,22 +29,24 @@ package factor; +import factor.compiler.LocalAllocator; import java.lang.reflect.*; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import org.objectweb.asm.*; /** * A few methods for converting between Java types, and making reflection calls. * Note that the compiler incorporates calls to some of these methods in * generated bytecode. */ -public class FactorJava +public class FactorJava implements Constants { public static final Class[] EMPTY_ARRAY = new Class[0]; //{{{ classNameToClassList() method - public static Class[] classNameToClassList(FactorList classes) + public static Class[] classNameToClassList(Cons classes) throws Exception { if(classes == null) @@ -54,7 +56,31 @@ public class FactorJava int i = 0; while(classes != null) { - _classes[i++] = (Class)classes.car(Class.class); + Object car = classes.car; + if(car instanceof Cons) + { + Cons classSpec = (Cons)car; + if(classSpec.cdr != null) + { + throw new FactorRuntimeException( + "Bad class spec: " + car); + } + Class clazz = (Class)classSpec.car(Class.class); + if(clazz.isPrimitive()) + { + _classes[i] = getClass("[" + + javaClassToVMClass(clazz)); + } + else + { + _classes[i] = getClass("[L" + + clazz.getName() + ";"); + } + } + else + _classes[i] = (Class)classes.car(Class.class); + + i++; classes = classes.next(); } @@ -183,6 +209,29 @@ public class FactorJava } } //}}} + //{{{ toNamespace() method + public static FactorNamespace toNamespace(Object obj, + FactorInterpreter interp) throws Exception + { + if(obj instanceof FactorNamespace) + return (FactorNamespace)obj; + else if(obj instanceof FactorObject) + { + FactorNamespace ns = ((FactorObject)obj) + .getNamespace(interp); + if(ns == null) + throw new FactorRuntimeException( + obj + " has a null" + + " namespace"); + return ns; + } + else + { + throw new FactorDomainException(obj, + FactorObject.class); + } + } //}}} + //{{{ toArray() method public static Object[] toArray(Object arg) throws FactorDomainException @@ -194,9 +243,9 @@ public class FactorJava public static Object[] toArray(Object arg, Class clas) throws FactorDomainException { - if(arg instanceof FactorList) + if(arg instanceof Cons) { - FactorList list = (FactorList)arg; + Cons list = (Cons)arg; Object[] array = (Object[]) Array.newInstance( clas.getComponentType(), @@ -205,7 +254,21 @@ public class FactorJava return array; } else if(arg.getClass().isArray()) - return (Object[])arg; + { + if(arg.getClass() == clas) + return (Object[])arg; + else + { + Object[] _arg = (Object[])arg; + Object[] array = (Object[]) + Array.newInstance( + clas.getComponentType(), + _arg.length); + System.arraycopy(arg,0,array,0, + _arg.length); + return array; + } + } else throw new FactorDomainException(arg,Object[].class); } //}}} @@ -296,7 +359,7 @@ public class FactorJava else if(obj instanceof Character) return "#\\" + ((Character)obj).charValue(); else - return "(" + obj + ")"; + return "( " + obj + " )"; } //}}} //{{{ javaClassToVMClass() method @@ -387,7 +450,7 @@ public class FactorJava } //}}} //{{{ jconstructor() method - public static Constructor jconstructor(String inClass, FactorList args) + public static Constructor jconstructor(String inClass, Cons args) throws Exception { return Class.forName(inClass).getConstructor( @@ -458,7 +521,7 @@ public class FactorJava //{{{ jmethod() method public static Method jmethod(String method, String inClass, - FactorList args) throws Exception + Cons args) throws Exception { return Class.forName(inClass).getMethod(method, classNameToClassList(args)); @@ -519,4 +582,126 @@ public class FactorJava else return e; } //}}} + + //{{{ generateFromConversion() method + /** + * Unbox value at top of the stack. + */ + public static void generateFromConversion(CodeVisitor mw, Class type) + throws Exception + { + if(type == Object.class) + return; + + String methodName = null; + boolean interpArg = false; + + if(type == Number.class) + methodName = "toNumber"; + else if(type == String.class) + methodName = "toString"; + else if(type == boolean.class) + methodName = "toBoolean"; + else if(type == char.class) + methodName = "toChar"; + else if(type == int.class) + methodName = "toInt"; + else if(type == long.class) + methodName = "toLong"; + else if(type == float.class) + methodName = "toFloat"; + else if(type == double.class) + methodName = "toDouble"; + else if(type == Class.class) + methodName = "toClass"; + else if(type == FactorNamespace.class) + { + methodName = "toNamespace"; + interpArg = true; + } + else if(type.isArray()) + methodName = "toArray"; + + if(methodName == null) + { + mw.visitTypeInsn(CHECKCAST, + type.getName() + .replace('.','/')); + } + else + { + if(interpArg) + { + mw.visitVarInsn(ALOAD,0); + mw.visitMethodInsn(INVOKESTATIC, + "factor/FactorJava", + methodName, + "(Ljava/lang/Object;Lfactor/FactorInterpreter;)" + + FactorJava.javaClassToVMClass(type)); + } + else + { + mw.visitMethodInsn(INVOKESTATIC, + "factor/FactorJava", + methodName, + "(Ljava/lang/Object;)" + + FactorJava.javaClassToVMClass(type)); + } + } + } //}}} + + //{{{ generateToConversionPre() method + /** + * Avoid having to deal with category 1/2 computational type + * distinction. + */ + public static boolean generateToConversionPre(CodeVisitor mw, + Class type) throws Exception + { + if(type != boolean.class) + { + Class boxingType = FactorJava.javaBoxingType(type); + if(boxingType != null) + { + String boxingName = boxingType.getName() + .replace('.','/'); + mw.visitTypeInsn(NEW,boxingName); + mw.visitInsn(DUP); + + return true; + } + } + + return false; + } //}}} + + //{{{ generateToConversion() method + /** + * Box return value, if needed. + */ + public static void generateToConversion(CodeVisitor mw, Class type) + throws Exception + { + if(type == boolean.class) + { + // this case is handled specially + mw.visitMethodInsn(INVOKESTATIC, + "factor/FactorJava", + "fromBoolean", + "(Z)Ljava/lang/Object;"); + } + else + { + Class boxingType = FactorJava.javaBoxingType(type); + if(boxingType != null) + { + String boxingName = boxingType.getName() + .replace('.','/'); + mw.visitMethodInsn(INVOKESPECIAL,boxingName, + "", + "(" + FactorJava.javaClassToVMClass( + type) + ")V"); + } + } + } //}}} } diff --git a/factor/FactorLib.java b/factor/FactorLib.java index b2230d5bef..09528ca6ab 100644 --- a/factor/FactorLib.java +++ b/factor/FactorLib.java @@ -36,12 +36,6 @@ import java.io.*; */ public class FactorLib { - //{{{ branch2() method - public static Object branch2(boolean condition, Object o1, Object o2) - { - return (condition ? o1 : o2); - } //}}} - //{{{ branch3() method public static Object branch3(float x, float y, Object o1, Object o2, Object o3) @@ -54,36 +48,6 @@ public class FactorLib return o3; } //}}} - //{{{ cat() method - public static String cat(FactorList list) - { - StringBuffer buf = new StringBuffer(); - - while(list != null) - { - if(list.car instanceof FactorList) - buf.append(cat((FactorList)list.car)); - else - buf.append(list.car); - list = list.next(); - } - - return buf.toString(); - } //}}} - - //{{{ cat2() method - public static String cat2(Object str1, Object str2) - { - return new StringBuffer().append(str1).append(str2).toString(); - } //}}} - - //{{{ cat3() method - public static String cat3(Object str1, Object str2, Object str3) - { - return new StringBuffer().append(str1).append(str2).append(str3) - .toString(); - } //}}} - //{{{ cloneArray() method public static Object[] cloneArray(Object[] array) { diff --git a/factor/FactorMath.java b/factor/FactorMath.java index b03ceb6d0a..bcf9574ed7 100644 --- a/factor/FactorMath.java +++ b/factor/FactorMath.java @@ -3,7 +3,7 @@ /* * $Id$ * - * Copyright (C) 2003 Slava Pestov. + * Copyright (C) 2003,2004 Slava Pestov. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -282,6 +282,12 @@ public class FactorMath return min + Math.abs(nextInt % (max - min + 1)); } //}}} + //{{{ randomFloat() method + public static float randomFloat(int min, int max, float scale) + { + return randomInt(min,max) / scale; + } //}}} + //{{{ sgn() method public static int sgn(float num) { diff --git a/factor/FactorMissingDefinition.java b/factor/FactorMissingDefinition.java index 52c79b6837..c75d204183 100644 --- a/factor/FactorMissingDefinition.java +++ b/factor/FactorMissingDefinition.java @@ -3,7 +3,7 @@ /* * $Id$ * - * Copyright (C) 2003 Slava Pestov. + * Copyright (C) 2003, 2004 Slava Pestov. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,16 +29,22 @@ package factor; +import factor.compiler.*; +import java.util.Set; + /** * A placeholder for an undefined word. */ public class FactorMissingDefinition extends FactorWordDefinition { - public static final FactorMissingDefinition INSTANCE - = new FactorMissingDefinition(); + //{{{ FactorMissingDefinition constructor + public FactorMissingDefinition(FactorWord word) + { + super(word); + } //}}} //{{{ eval() method - public void eval(FactorWord word, FactorInterpreter interp) + public void eval(FactorInterpreter interp) throws FactorUndefinedWordException { throw new FactorUndefinedWordException(word); diff --git a/factor/FactorNamespace.java b/factor/FactorNamespace.java index 4bc89a7518..15726eded2 100644 --- a/factor/FactorNamespace.java +++ b/factor/FactorNamespace.java @@ -115,7 +115,7 @@ public class FactorNamespace implements PublicCloneable /** * Defines a variable bound to a Java field. */ - public void importVars(String clazz, FactorList vars) + public void importVars(String clazz, Cons vars) throws Exception { Class clas = Class.forName(clazz); @@ -157,16 +157,6 @@ public class FactorNamespace implements PublicCloneable return o; } //}}} - //{{{ _setVariable() method - /** - * Alternative form for bindings. - */ - public void _setVariable(Object value, String name) - throws Exception - { - setVariable(name,value); - } //}}} - //{{{ setVariable() method public void setVariable(String name, Object value) throws Exception @@ -214,10 +204,10 @@ public class FactorNamespace implements PublicCloneable /** * Returns a list of variable and word names defined in this namespace. */ - public FactorList toVarList() + public Cons toVarList() { - FactorList first = null; - FactorList last = null; + Cons first = null; + Cons last = null; Iterator iter = words.entrySet().iterator(); while(iter.hasNext()) { @@ -226,7 +216,7 @@ public class FactorNamespace implements PublicCloneable continue; String name = (String)entry.getKey(); - FactorList cons = new FactorList(name,null); + Cons cons = new Cons(name,null); if(first == null) first = last = cons; else @@ -243,10 +233,10 @@ public class FactorNamespace implements PublicCloneable /** * Returns a list of pairs of variable and word names, and their values. */ - public FactorList toValueList() + public Cons toValueList() { - FactorList first = null; - FactorList last = null; + Cons first = null; + Cons last = null; Iterator iter = words.entrySet().iterator(); while(iter.hasNext()) { @@ -254,8 +244,8 @@ public class FactorNamespace implements PublicCloneable if(entry.getValue() == CHECK_PARENT) continue; - FactorList cons = new FactorList( - new FactorList(entry.getKey(), + Cons cons = new Cons( + new Cons(entry.getKey(), entry.getValue()),null); if(first == null) first = last = cons; @@ -299,7 +289,13 @@ public class FactorNamespace implements PublicCloneable //{{{ toString() method public String toString() { - return "Namespace[" + obj + "]"; + if(obj == null) + { + return "( Namespace #" + Integer.toString(hashCode(),16) + + " )"; + } + else + return "( Namespace: " + obj + " #" + hashCode() + " )"; } //}}} //{{{ clone() method diff --git a/factor/FactorParser.java b/factor/FactorParser.java index eb40d57730..c083b297d1 100644 --- a/factor/FactorParser.java +++ b/factor/FactorParser.java @@ -108,10 +108,10 @@ public class FactorParser * Reads the file being parsed, and returns a list of all tokens that * were read in. This list can be evaluated to run the file. */ - public FactorList parse() throws IOException, FactorParseException + public Cons parse() throws IOException, FactorParseException { - FactorList first = null; - FactorList last = null; + Cons first = null; + Cons last = null; try { @@ -131,12 +131,15 @@ public class FactorParser error("Expected word name after " + next); } - FactorWordDefinition def = readDef(); + FactorWord word = (FactorWord)obj; - FactorList l = new FactorList(DEFINE,null); - FactorList cons = new FactorList( - ((FactorWord)obj).name, - new FactorList(def,l)); + FactorWordDefinition def + = readDef(word); + + Cons l = new Cons(DEFINE,null); + Cons cons = new Cons( + word.name, + new Cons(def,l)); if(first == null) first = cons; else @@ -152,12 +155,15 @@ public class FactorParser error("Expected word name after " + next); } - FactorWordDefinition def = readShuffle(); + FactorWord word = (FactorWord)obj; - FactorList l = new FactorList(DEFINE,null); - FactorList cons = new FactorList( - ((FactorWord)obj).name, - new FactorList(def,l)); + FactorWordDefinition def + = readShuffle(word); + + Cons l = new Cons(DEFINE,null); + Cons cons = new Cons( + word.name, + new Cons(def,l)); if(first == null) first = cons; else @@ -166,7 +172,7 @@ public class FactorParser } else if(next == BRA) { - FactorList cons = new FactorList( + Cons cons = new Cons( readList(),null); if(first == null) first = cons; @@ -180,7 +186,7 @@ public class FactorParser } else { - FactorList cons = new FactorList(next,null); + Cons cons = new Cons(next,null); if(first == null) first = cons; else @@ -323,10 +329,10 @@ public class FactorParser /** * Read list until ;. */ - private FactorWordDefinition readDef() + private FactorWordDefinition readDef(FactorWord word) throws IOException, FactorParseException { - return new FactorCompoundDefinition(readList(INE,false)); + return new FactorCompoundDefinition(word,readList(INE,false)); } //}}} //{{{ readShuffle() method @@ -336,7 +342,7 @@ public class FactorParser * On the left is inputs, on the right is their arrangement on the * stack. */ - private FactorWordDefinition readShuffle() + private FactorWordDefinition readShuffle(FactorWord word) throws IOException, FactorParseException { // 0 in consume map is last consumed, n is first consumed. @@ -377,13 +383,14 @@ public class FactorParser } } - FactorList _shuffle = readList(FLE,false); + Cons _shuffle = readList(FLE,false); int consume = consumeMap.size(); if(_shuffle == null) { - return new FactorShuffleDefinition(consumeD,consumeR, + return new FactorShuffleDefinition(word, + consumeD,consumeR, null,0,null,0); } @@ -397,12 +404,12 @@ public class FactorParser { if(_shuffle.car instanceof FactorWord) { - FactorWord word = ((FactorWord)_shuffle.car); - String name = word.name; + FactorWord w = ((FactorWord)_shuffle.car); + String name = w.name; if(name.startsWith("r:")) - word = dict.intern(name.substring(2)); + w = dict.intern(name.substring(2)); - Integer _index = (Integer)consumeMap.get(word); + Integer _index = (Integer)consumeMap.get(w); if(_index == null) error("Does not appear in shuffle LHS: " + _shuffle.car); int index = _index.intValue(); @@ -445,7 +452,7 @@ public class FactorParser shuffleD[k++] = index; } - return new FactorShuffleDefinition(consumeD,consumeR, + return new FactorShuffleDefinition(word,consumeD,consumeR, shuffleD,shuffleDlength,shuffleR,shuffleRlength); } //}}} @@ -453,7 +460,7 @@ public class FactorParser /** * Read list until ]. */ - private FactorList readList() + private Cons readList() throws IOException, FactorParseException { return readList(KET,true); @@ -463,11 +470,11 @@ public class FactorParser /** * Read list until a given word. */ - private FactorList readList(FactorWord until, boolean allowCommaPair) + private Cons readList(FactorWord until, boolean allowCommaPair) throws IOException, FactorParseException { - FactorList first = null; - FactorList last = null; + Cons first = null; + Cons last = null; for(;;) { @@ -509,12 +516,12 @@ public class FactorParser } else if(next == BRA) { - FactorList list = readList(); + Cons list = readList(); if(first == null) - first = last = new FactorList(list,null); + first = last = new Cons(list,null); else { - FactorList nextList = new FactorList(list,null); + Cons nextList = new Cons(list,null); last.cdr = nextList; last = nextList; } @@ -522,10 +529,10 @@ public class FactorParser else if(isParsingWord(next)) error("Unexpected " + next); else if(first == null) - first = last = new FactorList(next,null); + first = last = new Cons(next,null); else { - FactorList nextList = new FactorList(next,null); + Cons nextList = new Cons(next,null); last.cdr = nextList; last = nextList; } diff --git a/factor/FactorPrimitive.java b/factor/FactorPrimitive.java deleted file mode 100644 index 8e4635c9b2..0000000000 --- a/factor/FactorPrimitive.java +++ /dev/null @@ -1,374 +0,0 @@ -/* :folding=explicit:collapseFolds=1: */ - -/* - * $Id$ - * - * Copyright (C) 2003 Slava Pestov. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package factor; - -import java.lang.reflect.*; - -public abstract class FactorPrimitive extends FactorWordDefinition -{ - //{{{ P_callstackGet class - static class P_callstackGet extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - interp.datastack.push(interp.callstack.clone()); - } - } //}}} - - //{{{ P_callstackSet class - static class P_callstackSet extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - interp.callstack = (FactorCallStack)((FactorCallStack) - interp.datastack.pop(FactorCallStack.class)) - .clone(); - } - } //}}} - - //{{{ P_datastackGet class - static class P_datastackGet extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - interp.datastack.push(interp.datastack.clone()); - } - } //}}} - - //{{{ P_datastackSet class - static class P_datastackSet extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - interp.datastack = (FactorDataStack)((FactorDataStack) - interp.datastack.pop(FactorDataStack.class)) - .clone(); - } - } //}}} - - //{{{ P_clear class - static class P_clear extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - interp.datastack.top = 0; - } - } //}}} - - //{{{ P_restack class - static class P_restack extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - FactorList list = (FactorList)datastack.pop(FactorList.class); - interp.callstack.push(datastack); - interp.datastack = new FactorDataStack(list); - } - } //}}} - - //{{{ P_unstack class - static class P_unstack extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorList unstack = interp.datastack.toList(); - interp.datastack = (FactorDataStack)interp.callstack.pop(); - interp.datastack.push(unstack); - } - } //}}} - - //{{{ P_unwind class - static class P_unwind extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - interp.callstack.top = 0; - } - } //}}} - - //{{{ P_jconstructor class - static class P_jconstructor extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - datastack.push( - FactorJava.jconstructor( - (String)datastack.pop(String.class), - (FactorList)datastack.pop(FactorList.class))); - } - } //}}} - - //{{{ P_jfield class - static class P_jfield extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - datastack.push( - FactorJava.jfield( - (String)datastack.pop(String.class), - (String)datastack.pop(String.class))); - } - } //}}} - - //{{{ P_jinvoke class - static class P_jinvoke extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - FactorJava.jinvoke(datastack, - (Method)datastack.pop(), - datastack.pop()); - } - } //}}} - - //{{{ P_jinvokeStatic class - static class P_jinvokeStatic extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - FactorJava.jinvokeStatic(datastack, - (Method)datastack.pop()); - } - } //}}} - - //{{{ P_jmethod class - static class P_jmethod extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - datastack.push( - FactorJava.jmethod( - (String)datastack.pop(String.class), - (String)datastack.pop(String.class), - (FactorList)datastack.pop(FactorList.class))); - } - } //}}} - - //{{{ P_jnew class - static class P_jnew extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - FactorJava.jnew(datastack, - (Constructor)datastack.pop()); - } - } //}}} - - //{{{ P_jvarGet class - static class P_jvarGet extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - datastack.push( - FactorJava.jvarGet( - (Field)datastack.pop(Field.class), - datastack.pop())); - } - } //}}} - - //{{{ P_jvarGetStatic class - static class P_jvarGetStatic extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - datastack.push( - FactorJava.jvarGetStatic( - (Field)datastack.pop(Field.class))); - } - } //}}} - - //{{{ P_jvarSet class - static class P_jvarSet extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - FactorJava.jvarSet( - (Field)datastack.pop(Field.class), - datastack.pop(), - datastack.pop()); - } - } //}}} - - //{{{ P_jvarSetStatic class - static class P_jvarSetStatic extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - FactorJava.jvarSetStatic( - (Field)datastack.pop(Field.class), - datastack.pop()); - } - } //}}} - - //{{{ P_get class - static class P_get extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - datastack.push(interp.callframe.namespace.getVariable( - (String)datastack.pop(String.class))); - } - } //}}} - - //{{{ P_set class - static class P_set extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - interp.callframe.namespace.setVariable( - (String)datastack.pop(String.class), - datastack.pop()); - } - } //}}} - - //{{{ P_swap_set class - static class P_swap_set extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - interp.callframe.namespace._setVariable(datastack.pop(), - (String)datastack.pop(String.class)); - } - } //}}} - - //{{{ P_define class - static class P_define extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - FactorDictionary dict = interp.dict; - // handle old define syntax - Object obj = datastack.pop(); - if(obj instanceof FactorList) - obj = new FactorCompoundDefinition((FactorList)obj); - FactorWordDefinition def = (FactorWordDefinition)obj; - - FactorWord newWord = interp.dict.intern( - (String)datastack.pop(String.class)); - - def.precompile(newWord,interp); - try - { - if(interp.compile) - def = def.compile(newWord,interp); - } - catch(Throwable t) - { - System.err.println("WARNING: cannot compile " + newWord); - t.printStackTrace(); - } - - if(newWord.def != FactorMissingDefinition.INSTANCE) - { - System.err.println("WARNING: redefining " + newWord); - newWord.history = new FactorList(newWord.def, - newWord.history); - } - newWord.def = def; - } - } //}}} - - //{{{ P_call class - static class P_call extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - interp.call(word,(FactorList)interp.datastack.pop( - FactorList.class)); - } - } //}}} - - //{{{ P_bind class - static class P_bind extends FactorPrimitive - { - public void eval(FactorWord word, FactorInterpreter interp) - throws Exception - { - FactorDataStack datastack = interp.datastack; - FactorList code = (FactorList)datastack.pop(FactorList.class); - Object obj = datastack.pop(); - FactorNamespace ns; - if(obj instanceof FactorNamespace) - ns = (FactorNamespace)obj; - else if(obj instanceof FactorObject) - { - ns = ((FactorObject)obj).getNamespace(interp); - if(ns == null) - throw new FactorRuntimeException( - obj + " has a null" - + " namespace"); - } - else - { - throw new FactorDomainException(obj, - FactorObject.class); - } - interp.call(word,ns,code); - } - } //}}} -} diff --git a/factor/FactorReflectionForm.java b/factor/FactorReflectionForm.java deleted file mode 100644 index d270a0282c..0000000000 --- a/factor/FactorReflectionForm.java +++ /dev/null @@ -1,394 +0,0 @@ -/* :folding=explicit:collapseFolds=1: */ - -/* -* $Id$ -* -* Copyright (C) 2003, 2004 Slava Pestov. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, -* this list of conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, -* this list of conditions and the following disclaimer in the documentation -* and/or other materials provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -* DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package factor; - -import java.lang.reflect.*; -import org.objectweb.asm.*; - -class FactorReflectionForm implements Constants -{ - private FactorList form; - - //{{{ FactorReflectionForm constructor - FactorReflectionForm(FactorList form) - { - this.form = form; - } //}}} - - //{{{ compile() method - boolean compile(FactorWord word, FactorInterpreter interp, - ClassWriter cw, CodeVisitor mw) - throws Exception - { - FactorDictionary dict = interp.dict; - if(form.car == dict.jvarGet) - { - return compileVarGet(word,interp,cw,mw, - form.next(),false); - } - else if(form.car == dict.jvarGetStatic) - { - return compileVarGet(word,interp,cw,mw, - form.next(),true); - } - else if(form.car == dict.jinvoke) - { - return compileInvoke(word,interp,cw,mw, - form.next(),false); - } - else if(form.car == dict.jinvokeStatic) - { - return compileInvoke(word,interp,cw,mw, - form.next(),true); - } - else if(form.car == dict.jnew) - { - return compileNew(word,interp,cw,mw, - form.next()); - } - else - throw new FactorRuntimeException("Cannot compile " + form.car); - } //}}} - - //{{{ compileVarGet() method - private boolean compileVarGet(FactorWord word, - FactorInterpreter interp, - ClassWriter cw, - CodeVisitor mw, - FactorList form, - boolean staticGet) throws Exception - { - FactorDictionary dict = interp.dict; - if(form.car != dict.jfield) - return false; - - form = form.next(); - String field = (String)form.car; - String clazz = (String)form.next().car; - - mw.visitVarInsn(ALOAD,2); - mw.visitFieldInsn(GETFIELD, - "factor/FactorInterpreter", "datastack", - "Lfactor/FactorDataStack;"); - - if(!staticGet) - { - mw.visitInsn(DUP); - mw.visitMethodInsn(INVOKEVIRTUAL, - "factor/FactorArrayStack", "pop", - "()Ljava/lang/Object;"); - } - - Class cls = FactorJava.getClass(clazz); - - generateFromConversion(mw,cls); - - Field fld = cls.getField(field); - - clazz = clazz.replace('.','/'); - - mw.visitFieldInsn(staticGet ? GETSTATIC : GETFIELD, - clazz, - field, - FactorJava.javaClassToVMClass(fld.getType())); - - generateToConversion(mw,fld.getType()); - - mw.visitMethodInsn(INVOKEVIRTUAL, - "factor/FactorArrayStack", "push", - "(Ljava/lang/Object;)V"); - - mw.visitInsn(RETURN); - - mw.visitMaxs(3,3); - - return true; - } //}}} - - //{{{ compileInvoke() method - private boolean compileInvoke(FactorWord word, - FactorInterpreter interp, - ClassWriter cw, - CodeVisitor mw, - FactorList form, - boolean staticInvoke) throws Exception - { - FactorDictionary dict = interp.dict; - if(form.car != dict.jmethod) - return false; - - form = form.next(); - String method = (String)form.car; - String clazz = (String)form.next().car; - Class[] args = FactorJava.classNameToClassList( - (FactorList)form.next().next().car); - - mw.visitVarInsn(ALOAD,2); - mw.visitFieldInsn(GETFIELD, - "factor/FactorInterpreter", "datastack", - "Lfactor/FactorDataStack;"); - - Class cls = FactorJava.getClass(clazz); - clazz = clazz.replace('.','/'); - - if(!staticInvoke) - { - mw.visitInsn(DUP); - mw.visitMethodInsn(INVOKEVIRTUAL, - "factor/FactorArrayStack", "pop", - "()Ljava/lang/Object;"); - generateFromConversion(mw,cls); - if(args.length != 0) - mw.visitInsn(SWAP); - } - - generateArgs(mw,args,!staticInvoke); - - Method mth = cls.getMethod(method,args); - - Class returnType = mth.getReturnType(); - int opcode; - if(staticInvoke) - opcode = INVOKESTATIC; - else if(cls.isInterface()) - opcode = INVOKEINTERFACE; - else - opcode = INVOKEVIRTUAL; - mw.visitMethodInsn(opcode, - clazz, - method, - FactorJava.javaSignatureToVMSignature( - args,returnType)); - - if(returnType != Void.TYPE) - { - generateToConversion(mw,returnType); - mw.visitMethodInsn(INVOKEVIRTUAL, - "factor/FactorArrayStack", "push", - "(Ljava/lang/Object;)V"); - } - else - mw.visitInsn(POP); - - mw.visitInsn(RETURN); - - mw.visitMaxs(4 + args.length,5); - - return true; - } //}}} - - //{{{ compileNew() method - private boolean compileNew(FactorWord word, - FactorInterpreter interp, - ClassWriter cw, - CodeVisitor mw, - FactorList form) throws Exception - { - FactorDictionary dict = interp.dict; - if(form.car != dict.jconstructor) - return false; - - form = form.next(); - String clazz = (String)form.car; - Class[] args = FactorJava.classNameToClassList( - (FactorList)form.next().car); - - clazz = clazz.replace('.','/'); - mw.visitTypeInsn(NEW,clazz); - mw.visitInsn(DUP); - - mw.visitVarInsn(ALOAD,2); - mw.visitFieldInsn(GETFIELD, - "factor/FactorInterpreter", "datastack", - "Lfactor/FactorDataStack;"); - - generateArgs(mw,args,true); - - mw.visitMethodInsn(INVOKESPECIAL, - clazz, - "", - FactorJava.javaSignatureToVMSignature( - args,void.class)); - - mw.visitInsn(SWAP); - mw.visitMethodInsn(INVOKEVIRTUAL, - "factor/FactorArrayStack", "push", - "(Ljava/lang/Object;)V"); - - mw.visitInsn(RETURN); - - mw.visitMaxs(5 + args.length,5); - - return true; - } //}}} - - //{{{ generateArgs() method - /** - * Generate instructions for copying arguments from the Factor - * datastack to the JVM stack. The types array is used to - * perform type conversions. - */ - private void generateArgs(CodeVisitor mw, Class[] args, - boolean generateSwap) throws Exception - { - if(args.length != 0) - { - // ensure the stack has enough elements - mw.visitInsn(DUP); - mw.visitIntInsn(BIPUSH,args.length); - mw.visitMethodInsn(INVOKEVIRTUAL, - "factor/FactorArrayStack", "ensurePop", - "(I)V"); - - // datastack.stack -> 3 - mw.visitInsn(DUP); - mw.visitFieldInsn(GETFIELD, - "factor/FactorArrayStack", "stack", - "[Ljava/lang/Object;"); - mw.visitVarInsn(ASTORE,3); - // datastack.top-args.length -> 4 - mw.visitInsn(DUP); - mw.visitFieldInsn(GETFIELD, - "factor/FactorArrayStack", "top", - "I"); - mw.visitIntInsn(BIPUSH,args.length); - mw.visitInsn(ISUB); - - // datastack.top -= args.length - mw.visitInsn(DUP2); - mw.visitFieldInsn(PUTFIELD, - "factor/FactorArrayStack", "top", - "I"); - - mw.visitVarInsn(ISTORE,4); - - if(generateSwap) - mw.visitInsn(SWAP); - - for(int i = 0; i < args.length; i++) - { - mw.visitVarInsn(ALOAD,3); - mw.visitVarInsn(ILOAD,4); - mw.visitInsn(AALOAD); - generateFromConversion(mw,args[i]); - if(i != args.length - 1) - mw.visitIincInsn(4,1); - } - } - } //}}} - - //{{{ generateFromConversion() method - /** - * Unbox value at top of the stack. - */ - private void generateFromConversion(CodeVisitor mw, Class type) - throws Exception - { - if(type == Object.class) - return; - - String methodName = null; - - if(type == Number.class) - methodName = "toNumber"; - else if(type == String.class) - methodName = "toString"; - else if(type == boolean.class) - methodName = "toBoolean"; - else if(type == char.class) - methodName = "toChar"; - else if(type == int.class) - methodName = "toInt"; - else if(type == long.class) - methodName = "toLong"; - else if(type == float.class) - methodName = "toFloat"; - else if(type == double.class) - methodName = "toDouble"; - else if(type == Class.class) - methodName = "toClass"; - else if(type.isArray()) - methodName = "toArray"; - - if(methodName == null) - { - mw.visitTypeInsn(CHECKCAST, - type.getName() - .replace('.','/')); - } - else - { - mw.visitMethodInsn(INVOKESTATIC, - "factor/FactorJava", - methodName, - "(Ljava/lang/Object;)" - + FactorJava.javaClassToVMClass(type)); - } - } //}}} - - //{{{ generateToConversion() method - /** - * Box return value, if needed. - */ - private void generateToConversion(CodeVisitor mw, Class type) - throws Exception - { - if(type == boolean.class) - { - // this case is handled specially - mw.visitMethodInsn(INVOKESTATIC, - "factor/FactorJava", - "fromBoolean", - "(Z)Ljava/lang/Object;"); - } - else - { - Class boxingType = FactorJava.javaBoxingType(type); - if(boxingType != null) - { - String boxingName = boxingType.getName() - .replace('.','/'); - mw.visitTypeInsn(NEW,boxingName); - mw.visitInsn(DUP_X1); - mw.visitInsn(SWAP); - mw.visitMethodInsn(INVOKESPECIAL,boxingName, - "", - "(" + FactorJava.javaClassToVMClass( - type) + ")V"); - } - } - } //}}} - - //{{{ toString() method - public String toString() - { - return form.toString(); - } //}}} -} diff --git a/factor/FactorShuffleDefinition.java b/factor/FactorShuffleDefinition.java index cfd03e33c9..d75f4371ca 100644 --- a/factor/FactorShuffleDefinition.java +++ b/factor/FactorShuffleDefinition.java @@ -29,7 +29,10 @@ package factor; +import factor.compiler.*; +import java.util.Set; import org.objectweb.asm.*; +import org.objectweb.asm.util.*; /** * ~<< name ... -- >>~ @@ -63,10 +66,13 @@ public class FactorShuffleDefinition extends FactorWordDefinition private Object[] temporaryR; //{{{ FactorShuffleDefinition constructor - public FactorShuffleDefinition(int consumeD, int consumeR, + public FactorShuffleDefinition(FactorWord word, + int consumeD, int consumeR, int[] shuffleD, int shuffleDlength, int[] shuffleR, int shuffleRlength) { + super(word); + this.consumeD = consumeD; this.consumeR = consumeR; this.shuffleD = shuffleD; @@ -102,295 +108,49 @@ public class FactorShuffleDefinition extends FactorWordDefinition } } //}}} - //{{{ canCompile() method - boolean canCompile() + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws FactorStackException { - return true; + state.ensure(state.datastack,consumeD); + state.ensure(state.callstack,consumeR); + eval(state.datastack,state.callstack); + return new StackEffect(consumeD,shuffleDlength, + consumeR,shuffleRlength); } //}}} //{{{ compile() method /** - * Write the definition of the eval() method in the compiled word. - * Local 0 -- this - * Local 1 -- word - * Local 2 -- interpreter + * Compile the given word, returning a new word definition. */ - boolean compile(FactorWord word, FactorInterpreter interp, - ClassWriter cw, CodeVisitor mw) - throws Exception + FactorWordDefinition compile(FactorInterpreter interp, + Set recursiveCheck) throws Exception { - boolean fromD = false; - boolean fromR = false; - for(int i = 0; i < shuffleDlength; i++) - { - fromD = true; - if((shuffleD[i] & FROM_R_MASK) == FROM_R_MASK) - { - fromR = true; - break; - } - } - for(int i = 0; i < shuffleRlength; i++) - { - fromR = true; - if((shuffleR[i] & FROM_R_MASK) == FROM_R_MASK) - { - fromR = true; - break; - } - } + return this; + } //}}} - // Local 3 -- datastack - // Local 4 -- datastack top-consumeD - // Local 5 -- datastack array - if(consumeD != 0 || fromD) - { - // (datastack datastack datastack) - mw.visitVarInsn(ALOAD,2); - mw.visitFieldInsn(GETFIELD, - "factor/FactorInterpreter", "datastack", - "Lfactor/FactorDataStack;"); - mw.visitInsn(DUP); - if(consumeD != 0) - { - mw.visitInsn(DUP); - mw.visitIntInsn(BIPUSH,consumeD); - mw.visitMethodInsn(INVOKEVIRTUAL, - "factor/FactorArrayStack", "ensurePop", - "(I)V"); - } - - mw.visitInsn(DUP); - // datastack -> 3 - mw.visitVarInsn(ASTORE,3); - // datastack.top-consumeD -> 4 - mw.visitFieldInsn(GETFIELD, - "factor/FactorArrayStack", "top", - "I"); - if(consumeD != 0) - { - mw.visitIntInsn(BIPUSH,consumeD); - mw.visitInsn(ISUB); - } - mw.visitVarInsn(ISTORE,4); - // datastack.stack -> 5 - mw.visitFieldInsn(GETFIELD, - "factor/FactorArrayStack", "stack", - "[Ljava/lang/Object;"); - mw.visitVarInsn(ASTORE,5); - } - - // Local 6 -- callstack - // Local 7 -- callstack top-consumeR - // Local 8 -- callstack array - if(consumeR != 0 || fromR) - { - // (callstack callstack) - mw.visitVarInsn(ALOAD,2); - mw.visitFieldInsn(GETFIELD, - "factor/FactorInterpreter", "callstack", - "Lfactor/FactorCallStack;"); - mw.visitInsn(DUP); - if(consumeR != 0) - { - mw.visitInsn(DUP); - mw.visitIntInsn(BIPUSH,consumeR); - mw.visitMethodInsn(INVOKEVIRTUAL, - "factor/FactorArrayStack", "ensurePop", - "(I)V"); - } - - mw.visitInsn(DUP); - // callstack -> 6 - mw.visitVarInsn(ASTORE,6); - // callstack.top-consumeR -> 7 - mw.visitFieldInsn(GETFIELD, - "factor/FactorArrayStack", "top", - "I"); - if(consumeR != 0) - { - mw.visitIntInsn(BIPUSH,consumeR); - mw.visitInsn(ISUB); - } - mw.visitVarInsn(ISTORE,7); - // callstack.stack -> 8 - mw.visitFieldInsn(GETFIELD, - "factor/FactorArrayStack", "stack", - "[Ljava/lang/Object;"); - mw.visitVarInsn(ASTORE,8); - } - - int locals = 9; - - if(shuffleD != null) - { - for(int i = shuffleDstart; i < shuffleDlength; i++) - { - // stack[top-consumeD+shuffleD[i]] -> 9+i - int index = shuffleD[i]; - if((index & FROM_R_MASK) == FROM_R_MASK) - { - mw.visitVarInsn(ALOAD,8); - mw.visitVarInsn(ILOAD,7); - index &= ~FROM_R_MASK; - } - else - { - mw.visitVarInsn(ALOAD,5); - mw.visitVarInsn(ILOAD,4); - } - - if(index != 0) - { - mw.visitIntInsn(BIPUSH,index); - mw.visitInsn(IADD); - } - - mw.visitInsn(AALOAD); - mw.visitVarInsn(ASTORE,9 + i); - } - - locals += shuffleDlength; - } - - if(shuffleR != null) - { - for(int i = shuffleRstart; i < shuffleRlength; i++) - { - // stack[top-consumeR+shuffleR[i]] -> 9+i - int index = shuffleR[i]; - if((index & FROM_R_MASK) == FROM_R_MASK) - { - mw.visitVarInsn(ALOAD,8); - mw.visitVarInsn(ILOAD,7); - index &= ~FROM_R_MASK; - } - else - { - mw.visitVarInsn(ALOAD,5); - mw.visitVarInsn(ILOAD,4); - } - - if(index != 0) - { - mw.visitIntInsn(BIPUSH,index); - mw.visitInsn(IADD); - } - - mw.visitInsn(AALOAD); - mw.visitVarInsn(ASTORE,locals + i); - } - } - - if(shuffleD != null) - { - // ensure that the stack array has enough space. - mw.visitVarInsn(ALOAD,3); - mw.visitInsn(DUP); - mw.visitIntInsn(BIPUSH,shuffleDlength); - mw.visitMethodInsn(INVOKEVIRTUAL, - "factor/FactorArrayStack", "ensurePush", "(I)V"); - // the datastack.stack array might have changed. - // reload it. - mw.visitFieldInsn(GETFIELD, - "factor/FactorArrayStack", "stack", - "[Ljava/lang/Object;"); - mw.visitVarInsn(ASTORE,5); - - for(int i = shuffleDstart; i < shuffleDlength; i++) - { - // stack[top - consumeD + i] <- 9+i - mw.visitVarInsn(ALOAD,5); - mw.visitVarInsn(ILOAD,4); - if(i != 0) - { - mw.visitIntInsn(BIPUSH,i); - mw.visitInsn(IADD); - } - mw.visitVarInsn(ALOAD,9 + i); - mw.visitInsn(AASTORE); - } - - // increment the 'top' field. - mw.visitVarInsn(ALOAD,3); - mw.visitVarInsn(ILOAD,4); - mw.visitIntInsn(BIPUSH,shuffleDlength); - mw.visitInsn(IADD); - mw.visitFieldInsn(PUTFIELD, - "factor/FactorArrayStack", "top", - "I"); - } - else if(consumeD != 0) - { - mw.visitVarInsn(ALOAD,3); - mw.visitVarInsn(ILOAD,4); - mw.visitFieldInsn(PUTFIELD, - "factor/FactorArrayStack", "top", - "I"); - } - - if(shuffleR != null) - { - // ensure that the stack array has enough space. - mw.visitVarInsn(ALOAD,6); - mw.visitInsn(DUP); - mw.visitIntInsn(BIPUSH,shuffleDlength); - mw.visitMethodInsn(INVOKEVIRTUAL, - "factor/FactorArrayStack", "ensurePush", "(I)V"); - // the callstack.stack array might have changed. - // reload it. - mw.visitFieldInsn(GETFIELD, - "factor/FactorArrayStack", "stack", - "[Ljava/lang/Object;"); - mw.visitVarInsn(ASTORE,8); - - for(int i = shuffleRstart; i < shuffleRlength; i++) - { - // stack[top - consumeD + i] <- locals+i - mw.visitVarInsn(ALOAD,8); - mw.visitVarInsn(ILOAD,7); - if(i != 0) - { - mw.visitIntInsn(BIPUSH,i); - mw.visitInsn(IADD); - } - mw.visitVarInsn(ALOAD,locals + i); - mw.visitInsn(AASTORE); - } - - // increment the 'top' field. - mw.visitVarInsn(ALOAD,6); - mw.visitVarInsn(ILOAD,7); - mw.visitIntInsn(BIPUSH,shuffleRlength); - mw.visitInsn(IADD); - mw.visitFieldInsn(PUTFIELD, - "factor/FactorArrayStack", "top", - "I"); - } - else if(consumeR != 0) - { - mw.visitVarInsn(ALOAD,6); - mw.visitVarInsn(ILOAD,7); - mw.visitFieldInsn(PUTFIELD, - "factor/FactorArrayStack", "top", - "I"); - } - - mw.visitInsn(RETURN); - - // Max stack and locals - mw.visitMaxs(4,9 + shuffleDlength + shuffleRlength); - - return true; + //{{{ compileCallTo() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + */ + public int compileCallTo(CodeVisitor mw, LocalAllocator allocator, + Set recursiveCheck) throws FactorStackException + { + eval(allocator.datastack,allocator.callstack); + return 0; } //}}} //{{{ eval() method - public void eval(FactorWord word, FactorInterpreter interp) + public void eval(FactorInterpreter interp) throws FactorStackException { - FactorArrayStack datastack = interp.datastack; - FactorArrayStack callstack = interp.callstack; + eval(interp.datastack,interp.callstack); + } //}}} + //{{{ eval() method + public void eval(FactorArrayStack datastack, FactorArrayStack callstack) + throws FactorStackException + { if(datastack.top < consumeD) throw new FactorStackException(consumeD); @@ -398,10 +158,16 @@ public class FactorShuffleDefinition extends FactorWordDefinition throw new FactorStackException(consumeR); if(shuffleD != null) - shuffle(interp,datastack,consumeD,consumeR,shuffleD,temporaryD); + { + shuffle(datastack,callstack,datastack,consumeD,consumeR, + shuffleD,temporaryD); + } if(shuffleR != null) - shuffle(interp,callstack,consumeD,consumeR,shuffleR,temporaryR); + { + shuffle(datastack,callstack,callstack,consumeD,consumeR, + shuffleR,temporaryR); + } datastack.top -= consumeD; if(temporaryD != null) @@ -414,8 +180,14 @@ public class FactorShuffleDefinition extends FactorWordDefinition } //}}} //{{{ shuffle() method - private void shuffle(FactorInterpreter interp, FactorArrayStack stack, - int consumeD, int consumeR, int[] shuffle, Object[] temporary) + private void shuffle( + FactorArrayStack datastack, + FactorArrayStack callstack, + FactorArrayStack stack, + int consumeD, + int consumeR, + int[] shuffle, + Object[] temporary) throws FactorStackException { for(int i = 0; i < temporary.length; i++) @@ -426,15 +198,15 @@ public class FactorShuffleDefinition extends FactorWordDefinition int consume; if((index & FROM_R_MASK) == FROM_R_MASK) { - array = interp.callstack.stack; - top = interp.callstack.top; + array = callstack.stack; + top = callstack.top; index = (index & ~FROM_R_MASK); consume = consumeR; } else { - array = interp.datastack.stack; - top = interp.datastack.top; + array = datastack.stack; + top = datastack.top; consume = consumeD; } temporary[i] = array[top - consume + index]; diff --git a/factor/FactorWord.java b/factor/FactorWord.java index 1929f109f9..26f2073c4a 100644 --- a/factor/FactorWord.java +++ b/factor/FactorWord.java @@ -29,8 +29,8 @@ package factor; -import java.util.HashMap; -import java.util.Map; +import factor.compiler.FactorCompilerException; +import java.util.*; /** * An internalized symbol. @@ -44,10 +44,20 @@ public class FactorWord implements FactorExternalizable */ public FactorWordDefinition def; + /** + * Definition before compiling. + */ + public FactorWordDefinition uncompiled; + /** * "define" pushes previous definitions onto this list, like a stack. */ - public FactorList history; + public Cons history; + + /** + * Is this word referenced from a compiled word? + */ + public boolean compileRef; //{{{ FactorWord constructor /** @@ -58,7 +68,64 @@ public class FactorWord implements FactorExternalizable public FactorWord(String name) { this.name = name; - def = FactorMissingDefinition.INSTANCE; + def = new FactorMissingDefinition(this); + } //}}} + + //{{{ define() method + public void define(FactorWordDefinition def) + { + if(compileRef) + { + System.err.println("WARNING: " + this + + " is used in one or more compiled words; old definition will remain until full recompile"); + } + else if(!(this.def instanceof FactorMissingDefinition)) + { + System.err.println("WARNING: redefining " + this); + history = new Cons(this.def,history); + } + + uncompiled = this.def = def; + } //}}} + + //{{{ compile() method + public void compile(FactorInterpreter interp) + { + compile(interp,new HashSet()); + } //}}} + + //{{{ compile() method + public void compile(FactorInterpreter interp, Set recursiveCheck) + { + if(def.compileFailed) + return; + + System.err.println("Compiling " + this); + if(recursiveCheck.contains(this)) + System.err.println("WARNING: cannot compile recursive calls: " + this); + + try + { + recursiveCheck.add(this); + + def = def.compile(interp,recursiveCheck); + } + catch(FactorCompilerException e) + { + def.compileFailed = true; + System.err.println("WARNING: cannot compile " + this); + System.err.println(e.getMessage()); + } + catch(Throwable t) + { + def.compileFailed = true; + System.err.println("WARNING: cannot compile " + this); + t.printStackTrace(); + } + finally + { + recursiveCheck.remove(this); + } } //}}} //{{{ toString() method diff --git a/factor/FactorWordDefinition.java b/factor/FactorWordDefinition.java index 7dec13c5b5..1196ed4247 100644 --- a/factor/FactorWordDefinition.java +++ b/factor/FactorWordDefinition.java @@ -3,7 +3,7 @@ /* * $Id$ * - * Copyright (C) 2003 Slava Pestov. + * Copyright (C) 2003, 2004 Slava Pestov. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,10 +29,10 @@ package factor; -import java.io.FileOutputStream; -import java.util.Iterator; +import factor.compiler.*; +import java.util.HashSet; +import java.util.Set; import org.objectweb.asm.*; -import org.objectweb.asm.util.*; /** * A word definition. @@ -40,152 +40,89 @@ import org.objectweb.asm.util.*; public abstract class FactorWordDefinition implements FactorObject, Constants { private FactorNamespace namespace; + protected FactorWord word; - /** - * Number of times this word has been referenced from a - * compound word (incremented by the precompiler). - */ - public int references; + public boolean compileFailed; - public abstract void eval(FactorWord word, FactorInterpreter interp) + public FactorWordDefinition(FactorWord word) + { + this.word = word; + } + + public abstract void eval(FactorInterpreter interp) throws Exception; - void precompile(FactorWord word, FactorInterpreter interp) - throws Exception {} - + //{{{ getNamespace() method public FactorNamespace getNamespace(FactorInterpreter interp) throws Exception { if(namespace == null) namespace = new FactorNamespace(interp.global,this); return namespace; - } - - //{{{ canCompile() method - boolean canCompile() - { - return false; } //}}} - private static int compileCount; - - //{{{ compile() method - /** - * Compile the given word, returning a new word definition. - */ - FactorWordDefinition compile(FactorWord word, FactorInterpreter interp) - throws Exception + //{{{ getStackEffect() method + public final StackEffect getStackEffect() throws Exception { - if(!canCompile()) - return this; + return getStackEffect(new HashSet(),new LocalAllocator()); + } //}}} - //System.out.println("Compiling " + word); - - StringBuffer sanitizedName = new StringBuffer(); - for(int i = 0; i < word.name.length(); i++) - { - char ch = word.name.charAt(i); - if(!Character.isJavaIdentifierStart(ch)) - sanitizedName.append("_"); - else - sanitizedName.append(ch); - } - String className = "factor/__compiler__/" + sanitizedName - + "_" + (compileCount++); - - ClassWriter cw = new ClassWriter(false); - cw.visit(ACC_PUBLIC, className, - "factor/FactorWordDefinition", null, null); - - // creates a MethodWriter for the (implicit) constructor - CodeVisitor mw = cw.visitMethod(ACC_PUBLIC, - "", "()V", null, null); - // pushes the 'this' variable - mw.visitVarInsn(ALOAD, 0); - // invokes the super class constructor - mw.visitMethodInsn(INVOKESPECIAL, - "factor/FactorWordDefinition", "", "()V"); - mw.visitInsn(RETURN); - // this code uses a maximum of one stack element and one local - // variable - mw.visitMaxs(1, 1); - - // creates a MethodWriter for the 'toString' method - mw = cw.visitMethod(ACC_PUBLIC, - "toString", "()Ljava/lang/String;", null, null); - mw.visitLdcInsn("( compiled ) " + toString()); - mw.visitInsn(ARETURN); - mw.visitMaxs(1, 1); - - // pushes the 'this' variable - mw.visitVarInsn(ALOAD, 0); - // invokes the super class constructor - mw.visitMethodInsn(INVOKESPECIAL, - "factor/FactorWordDefinition", "", "()V"); - mw.visitInsn(RETURN); - // this code uses a maximum of one stack element and one local - // variable - mw.visitMaxs(1, 1); - - // creates a MethodWriter for the 'eval' method - mw = cw.visitMethod(ACC_PUBLIC, - "eval", "(Lfactor/FactorWord;Lfactor/FactorInterpreter;)V", - null, null); - - // We store a string with disassembly for debugging - // purposes. - TraceCodeVisitor disasm = new TraceCodeVisitor(mw); - if(!compile(word,interp,cw,disasm)) - return this; - - // Save the disassembly - StringBuffer buf = new StringBuffer(); - Iterator bytecodes = disasm.getText().iterator(); - while(bytecodes.hasNext()) - { - buf.append(bytecodes.next()); - } - - // gets the bytecode of the class, and loads it dynamically - byte[] code = cw.toByteArray(); - - /* FileOutputStream fos = new FileOutputStream(className + ".class"); - fos.write(code); - fos.close(); */ - - SimpleClassLoader loader = new SimpleClassLoader(); - Class compiledWordClass = loader._defineClass(className, - code, 0, code.length); - - FactorWordDefinition compiledWord = (FactorWordDefinition) - compiledWordClass.newInstance(); - - compiledWord.getNamespace(interp).setVariable("asm",buf.toString()); - - return compiledWord; + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws Exception + { + return null; } //}}} //{{{ compile() method - /** - * Write the definition of the eval() method in the compiled word. - * Local 0 -- this - * Local 1 -- word - * Local 2 -- interpreter - */ - boolean compile(FactorWord word, FactorInterpreter interp, - ClassWriter cw, CodeVisitor mw) - throws Exception + FactorWordDefinition compile(FactorInterpreter interp, + Set recursiveCheck) throws Exception { - throw new FactorRuntimeException("Don't know how to compile " + word); + return this; } //}}} - //{{{ SimpleClassLoader class - static class SimpleClassLoader extends ClassLoader + //{{{ compileCallTo() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + */ + public int compileCallTo(CodeVisitor mw, LocalAllocator allocator, + Set recursiveCheck) throws Exception { - public Class _defineClass(String name, - byte[] code, int off, int len) + StackEffect effect = getStackEffect(); + if(effect == null) { - return defineClass(name,code,off,len); + // combinator; inline + return compileImmediate(mw,allocator,recursiveCheck); } + else + { + // normal word + mw.visitVarInsn(ALOAD,0); + + allocator.generateArgs(mw,effect.inD,null); + + String defclass = getClass().getName().replace('.','/'); + + String signature = effect.getCorePrototype(); + + mw.visitMethodInsn(INVOKESTATIC,defclass,"core",signature); + + if(effect.outD > 1) + throw new FactorCompilerException("Cannot compile word with non-0/1-out factors"); + if(effect.outD == 1) + allocator.push(mw); + + return effect.inD + 1; + } + } //}}} + + //{{{ compileImmediate() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + */ + public int compileImmediate(CodeVisitor mw, LocalAllocator allocator, + Set recursiveCheck) throws Exception + { + throw new FactorCompilerException("Cannot compile " + word + " in immediate mode"); } //}}} } diff --git a/factor/boot.factor b/factor/boot.factor index 947c0be553..ba4aa28c84 100644 --- a/factor/boot.factor +++ b/factor/boot.factor @@ -28,28 +28,30 @@ !!! The stack operators are defined using shuffle notation. This saves several !!! hundred lines of code! -~<< drop A -- >>~ -~<< 2drop A B -- >>~ -~<< dup A -- A A >>~ -~<< 2dup A B -- A B A B >>~ -~<< dupd A B -- A A B >>~ -~<< 2dupd A B C D -- A B A B C D >>~ -~<< nip A B -- B >>~ -~<< 2nip A B C D -- C D >>~ -~<< nop -- >>~ ! Does nothing! -~<< over A B -- A B A >>~ -~<< 2over A B C D -- A B C D A B >>~ -~<< pick A B C -- A B C A >>~ ! Not the Forth pick! -~<< rot A B C -- B C A >>~ -~<< 2rot A B C D E F -- C D E F A B >>~ -~<< -rot A B C -- C A B >>~ -~<< 2-rot A B C D E F -- E F A B C D >>~ -~<< swap A B -- B A >>~ -~<< 2swap A B C D -- C D A B >>~ -~<< swapd A B C -- B A C >>~ -~<< 2swapd A B C D E F -- C D A B E F >>~ -~<< tuck A B -- B A B >>~ -~<< 2tuck A B C D -- C D A B C D >>~ +~<< drop A -- >>~ +~<< 2drop A B -- >>~ +~<< dup A -- A A >>~ +~<< 2dup A B -- A B A B >>~ +~<< dupd A B -- A A B >>~ +~<< 2dupd A B C D -- A B A B C D >>~ +~<< nip A B -- B >>~ +~<< 2nip A B C D -- C D >>~ +~<< nop -- >>~ ! Does nothing! +~<< over A B -- A B A >>~ +~<< 2over A B C D -- A B C D A B >>~ +~<< pick A B C -- A B C A >>~ ! Not the Forth pick! +~<< rot A B C -- B C A >>~ +~<< 2rot A B C D E F -- C D E F A B >>~ +~<< -rot A B C -- C A B >>~ +~<< 2-rot A B C D E F -- E F A B C D >>~ +~<< swap A B -- B A >>~ +~<< 2swap A B C D -- C D A B >>~ +~<< swapd A B C -- B A C >>~ +~<< 2swapd A B C D E F -- C D A B E F >>~ +~<< transp A B C -- C B A >>~ +~<< 2transp A B C D E F -- E F C D A B >>~ +~<< tuck A B -- B A B >>~ +~<< 2tuck A B C D -- C D A B C D >>~ ~<< rdrop r:A -- >>~ ~<< >r A -- r:A >>~ @@ -60,21 +62,21 @@ !!! Minimum amount of I/O words needed to be able to read other resources. !!! Remaining I/O operations are defined in io.factor and parser.factor. : (reader -- breader) - [ |java.io.Reader ] |java.io.BufferedReader jconstructor jnew ; + [ |java.io.Reader ] |java.io.BufferedReader jnew ; : (inputstream -- breader) - [ |java.io.InputStream ] |java.io.InputStreamReader jconstructor jnew ; + [ |java.io.InputStream ] |java.io.InputStreamReader jnew ; : (path -- inputstream) |factor.FactorInterpreter - [ |java.lang.String ] |java.lang.Class |getResourceAsStream jmethod jinvoke + [ |java.lang.String ] |java.lang.Class |getResourceAsStream jinvoke ; : parse* (filename reader -- list) $dict [ |java.lang.String |java.io.Reader |factor.FactorDictionary ] - |factor.FactorParser jconstructor jnew - [ ] |factor.FactorParser |parse jmethod jinvoke ; + |factor.FactorParser jnew + [ ] |factor.FactorParser |parse jinvoke ; : runResource (path --) dup parse* call ; @@ -98,5 +100,20 @@ "/factor/stream.factor" runResource "/factor/strings.factor" runResource +: cli-param ( param -- ) + dup "no-" str-head? dup [ + f s@ drop + ] [ + drop t s@ + ] ifte ; + +: cli-arg ( argument -- boolean ) + "-" str-head? [ cli-param ] when* ; + +$args [ cli-arg ] each + +! Compile all words now +$compile [ compileAll ] when + ! If we're run stand-alone, start the interpreter in the current tty. $interactive [ initialInterpreterLoop ] when diff --git a/factor/combinators.factor b/factor/combinators.factor index b5f88db181..4d3e7bbc6b 100644 --- a/factor/combinators.factor +++ b/factor/combinators.factor @@ -90,18 +90,20 @@ ! [ [ condition 1 ] [ code 1 ] ! [ condition 2 ] [ code 2 ] ! ... ] - ! Each condition is evaluated in turn. If it returns true, the code - ! is evaluated. If it returns false, the next condition is checked. - [ - uncons >r - call - r> - swap [ + ! Each condition is evaluated in turn. If it returns true, + ! the code is evaluated. If it returns false, the next + ! condition is checked. Before evaluating each condition, + ! the top of the stack is duplicated. After the last + ! condition is evaluated, the top of the stack is popped. + dup [ + uncons [ over [ call ] dip ] dip rot [ car call ] [ cdr cond ] ifte - ] when* ; + ] [ + 2drop + ] ifte ; : dip (a [ b ] -- b a) ! Calls b as if b was not even present on the stack -- b has no way of @@ -122,14 +124,7 @@ : each ([ list ] [ code ] --) ! Applies the code to each element of the list. over [ - >r - uncons - r> - tuck - 2>r - call - 2r> - each + [ uncons ] dip tuck [ call ] 2dip each ] [ 2drop ] ifte ; @@ -143,6 +138,9 @@ call unstack ; +: ifte (cond [if true] [if false] --) + ? call ; + : interleave ( X list -- ... ) ! Evaluate each element of the list with X on top of the ! stack. @@ -152,9 +150,6 @@ 2drop ] ifte ; -: ifte (cond [if true] [if false] --) - ? call ; - : linrec ( [ P ] [ T ] [ R1 ] [ R2 ] -- ) ! Evaluate P, if it pushes t, evaluate T. Otherwise, evaluate R1, recurse, ! and evaluate R2. This combinator is similar to the linrec combinator in @@ -168,13 +163,10 @@ r> call ] ifte ; -: map ([ items ] [ initial ] [ code ] -- [ mapping ]) - ! Applies the code to each item, returns a list that begins with the initial - ! list and contains the result of each application. - swapd 2list append - restack - each - unstack ; +: map ( [ items ] [ code ] -- [ mapping ] ) + ! Applies the code to each item, returns a list that + ! contains the result of each application. + 2list restack each unstack ; : push ([ a b c ... ] -- a b c ...) ! Pushes values onto the stack literally (even if they are words). diff --git a/factor/compiler/CompiledDefinition.java b/factor/compiler/CompiledDefinition.java new file mode 100644 index 0000000000..00f27a9598 --- /dev/null +++ b/factor/compiler/CompiledDefinition.java @@ -0,0 +1,58 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* +* $Id$ +* +* Copyright (C) 2003, 2004 Slava Pestov. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package factor.compiler; + +import factor.*; +import java.lang.reflect.*; +import java.util.Set; +import org.objectweb.asm.*; + +/** + * : name ... ; + */ +public abstract class CompiledDefinition + extends FactorWordDefinition +{ + private StackEffect effect; + + //{{{ CompiledDefinition constructor + public CompiledDefinition(FactorWord word, StackEffect effect) + { + super(word); + this.effect = effect; + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) + { + return effect; + } //}}} +} diff --git a/factor/compiler/FactorCompilerException.java b/factor/compiler/FactorCompilerException.java new file mode 100644 index 0000000000..06a1138539 --- /dev/null +++ b/factor/compiler/FactorCompilerException.java @@ -0,0 +1,45 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.compiler; + +import factor.*; + +public class FactorCompilerException extends FactorRuntimeException +{ + public FactorCompilerException(String str) + { + super(str); + } + + public FactorCompilerException(String str, Throwable t) + { + super(str,t); + } +} diff --git a/factor/compiler/LocalAllocator.java b/factor/compiler/LocalAllocator.java new file mode 100644 index 0000000000..5684afddfa --- /dev/null +++ b/factor/compiler/LocalAllocator.java @@ -0,0 +1,677 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.compiler; + +import factor.*; +import java.lang.reflect.*; +import java.util.*; +import org.objectweb.asm.*; + +public class LocalAllocator implements Constants +{ + private FactorInterpreter interp; + + private String className; + private int base; + private int max; + + public FactorDataStack datastack; + public FactorCallStack callstack; + + private int literalCount; + private int wordCount; + + private Map literals = new HashMap(); + private Map words = new HashMap(); + + //{{{ LocalAllocator constructor + /** + * For balancing. + */ + public LocalAllocator() + { + this(null,null,0,0); + } //}}} + + //{{{ LocalAllocator constructor + /** + * For compiling. + */ + public LocalAllocator(FactorInterpreter interp, String className, + int base, int allot) + { + this.interp = interp; + this.className = className; + + this.base = base; + datastack = new FactorDataStack(); + callstack = new FactorCallStack(); + + for(int i = 0; i < allot; i++) + { + datastack.push(new Result(base + i)); + } + + max = base + allot; + + } //}}} + + //{{{ ensure() method + /** + * Ensure stack has at least 'count' elements. + * Eg, if count is 4 and stack is A B, + * stack will become RESULT RESULT A B. + * Used when deducing stack effects. + */ + public void ensure(FactorArrayStack stack, int count) + { + int top = stack.top; + if(top < count) + { + stack.ensurePush(count - top); + System.arraycopy(stack.stack,0,stack.stack, + count - top,top); + for(int i = 0; i < count - top; i++) + { + stack.stack[i] = new Result(allocate()); + } + stack.top = count; + } + } //}}} + + //{{{ compile() method + /** + * Compiles a quotation and returns the maximum JVM stack depth. + */ + public int compile(Cons definition, CodeVisitor mw, + Set recursiveCheck) throws Exception + { + int maxJVMStack = 0; + + while(definition != null) + { + Object obj = definition.car; + if(obj instanceof FactorWord) + { + FactorWord w = (FactorWord)obj; + + FactorWordDefinition d = w.def; + if(d instanceof FactorCompoundDefinition + && d.getStackEffect(recursiveCheck, + new LocalAllocator()) != null) + { + // compile first. + w.compile(interp,recursiveCheck); + if(w.def == d) + { + // didn't compile + throw new FactorCompilerException(w + " cannot be compiled"); + } + } + + maxJVMStack = Math.max(maxJVMStack, + w.def.compileCallTo(mw,this,recursiveCheck)); + } + else if(obj == null) + { + pushNull(); + } + else if(obj instanceof String) + { + pushString((String)obj); + } + else + { + pushLiteral(obj); + } + + definition = definition.next(); + } + + return maxJVMStack; + } //}}} + + //{{{ push() method + /** + * Generates code for pushing the top of the JVM stack onto the + * data stack. + */ + public void push(CodeVisitor mw) + { + int local = allocate(); + datastack.push(new Result(local)); + if(mw != null) + mw.visitVarInsn(ASTORE,local); + } //}}} + + //{{{ pushR() method + /** + * Generates code for pushing the top of the JVM stack onto the + * call stack. + */ + public void pushR(CodeVisitor mw) + { + int local = allocate(); + callstack.push(new Result(local)); + if(mw != null) + mw.visitVarInsn(ASTORE,local); + } //}}} + + //{{{ pushLiteral() method + public void pushLiteral(Object literal) + { + datastack.push(new Literal(literal)); + } //}}} + + //{{{ pushString() method + public void pushString(String literal) + { + datastack.push(new ConstantPoolString(literal)); + } //}}} + + //{{{ pushNull() method + public void pushNull() + { + datastack.push(new Null()); + } //}}} + + //{{{ pushChoice() method + public void pushChoice() throws FactorStackException + { + FlowObject f = (FlowObject)datastack.pop(); + FlowObject t = (FlowObject)datastack.pop(); + FlowObject cond = (FlowObject)datastack.pop(); + datastack.push(new Choice(cond,t,f)); + } //}}} + + //{{{ pop() method + /** + * Generates code for popping the top of the data stack onto + * the JVM stack. + */ + public void pop(CodeVisitor mw) throws FactorStackException + { + FlowObject obj = (FlowObject)datastack.pop(); + if(mw != null) + obj.generate(mw); + } //}}} + + //{{{ popR() method + /** + * Generates code for popping the top of the call stack onto + * the JVM stack. + */ + public void popR(CodeVisitor mw) throws FactorStackException + { + FlowObject obj = (FlowObject)callstack.pop(); + if(mw != null) + obj.generate(mw); + } //}}} + + //{{{ popLiteral() method + /** + * Pops a literal off the datastack or throws an exception. + */ + public Object popLiteral() throws FactorException + { + FlowObject obj = (FlowObject)datastack.pop(); + return obj.getLiteral(); + } //}}} + + //{{{ allocate() method + /** + * Allocate a local variable. + */ + private int allocate() + { + // inefficient! + int limit = base + datastack.top + callstack.top; + for(int i = base; i <= limit; i++) + { + if(allocate(i,datastack) && allocate(i,callstack)) + { + max = Math.max(max,i + 1); + return i; + } + } + // this is impossible + throw new RuntimeException("allocator failed"); + } //}}} + + //{{{ allocate() method + /** + * Return true if not in use, false if in use. + */ + private boolean allocate(int local, FactorArrayStack stack) + { + for(int i = 0; i < stack.top; i++) + { + FlowObject obj = (FlowObject)stack.stack[i]; + if(obj.usingLocal(local)) + return false; + } + return true; + } //}}} + + //{{{ maxLocals() method + public int maxLocals() + { + return max; + } //}}} + + //{{{ literal() method + private String literal(Object obj) + { + Integer i = (Integer)literals.get(obj); + int literal; + if(i == null) + { + literal = literalCount++; + literals.put(obj,new Integer(literal)); + } + else + literal = i.intValue(); + + return "literal_" + literal; + } //}}} + + //{{{ generateArgs() method + /** + * Generate instructions for copying arguments from the allocated + * local variables to the JVM stack, doing type conversion in the + * process. + */ + public void generateArgs(CodeVisitor mw, int num, Class[] args) + throws Exception + { + for(int i = 0; i < num; i++) + { + FlowObject obj = (FlowObject)datastack.stack[ + datastack.top - num + i]; + obj.generate(mw); + if(args != null) + FactorJava.generateFromConversion(mw,args[i]); + } + + datastack.top -= num; + } //}}} + + //{{{ generateFields() method + public void generateFields(ClassWriter cw) + throws Exception + { + for(int i = 0; i < literalCount; i++) + { + cw.visitField(ACC_PUBLIC | ACC_STATIC,"literal_" + i, + "Ljava/lang/Object;",null,null); + } + + Iterator entries = words.entrySet().iterator(); + while(entries.hasNext()) + { + Map.Entry entry = (Map.Entry)entries.next(); + FactorWord word = (FactorWord)entry.getKey(); + int index = ((Integer)entry.getValue()).intValue(); + + cw.visitField(ACC_PUBLIC | ACC_STATIC,"word_" + index, + FactorJava.javaClassToVMClass(word.def.getClass()), + null,null); + } + } //}}} + + //{{{ setFields() method + public void setFields(Class def) + throws Exception + { + Iterator entries = literals.entrySet().iterator(); + while(entries.hasNext()) + { + Map.Entry entry = (Map.Entry)entries.next(); + Object literal = entry.getKey(); + int index = ((Integer)entry.getValue()).intValue(); + + Field f = def.getField("literal_" + index); + f.set(null,literal); + } + + entries = words.entrySet().iterator(); + while(entries.hasNext()) + { + Map.Entry entry = (Map.Entry)entries.next(); + FactorWord word = (FactorWord)entry.getKey(); + int index = ((Integer)entry.getValue()).intValue(); + + Field f = def.getField("word_" + index); + System.err.println(word.def.getClass() + " ==> " + "word_" + index); + f.set(null,word.def); + } + } //}}} + + //{{{ FlowObject + public abstract class FlowObject + { + abstract void generate(CodeVisitor mw); + + boolean usingLocal(int local) + { + return false; + } + + Object getLiteral() + throws FactorCompilerException + { + throw new FactorCompilerException("Cannot compile unless literal on stack"); + } + + /** + * Stack effect of evaluating this -- only used for lists + * and conditionals! + */ + public StackEffect getStackEffect(Set recursiveCheck) + throws Exception + { + + return null; + } + + /** + * Write code for evaluating this. Returns maximum JVM stack + * usage. + */ + public int compileCallTo(CodeVisitor mw, Set recursiveCheck) + throws Exception + { + throw new FactorCompilerException("Cannot compile call to non-literal quotation"); + } + } //}}} + + //{{{ Result + class Result extends FlowObject + { + private int local; + + Result(int local) + { + this.local = local; + } + + void generate(CodeVisitor mw) + { + mw.visitVarInsn(ALOAD,local); + } + + boolean usingLocal(int local) + { + return (this.local == local); + } + } //}}} + + //{{{ Literal + class Literal extends FlowObject + { + private Object literal; + + Literal(Object literal) + { + this.literal = literal; + } + + void generate(CodeVisitor mw) + { + mw.visitFieldInsn(GETSTATIC,className, + literal(literal),"Ljava/lang/Object;"); + } + + Object getLiteral() + { + return literal; + } + + /** + * Stack effect of executing this -- only used for lists + * and conditionals! + */ + public StackEffect getStackEffect(Set recursiveCheck) + throws Exception + { + if(literal instanceof Cons + || literal == null) + { + return StackEffect.getStackEffect( + (Cons)literal,recursiveCheck, + LocalAllocator.this); + } + else + return null; + } + + /** + * Write code for evaluating this. Returns maximum JVM stack + * usage. + */ + public int compileCallTo(CodeVisitor mw, Set recursiveCheck) + throws Exception + { + if(literal instanceof Cons || literal == null) + return compile((Cons)literal,mw,recursiveCheck); + else + throw new FactorCompilerException("Not a quotation: " + literal); + } + } //}}} + + //{{{ ConstantPoolString + class ConstantPoolString extends FlowObject + { + private String str; + + ConstantPoolString(String str) + { + this.str = str; + } + + void generate(CodeVisitor mw) + { + mw.visitLdcInsn(str); + } + + Object getLiteral() + { + return str; + } + } //}}} + + //{{{ Null + class Null extends FlowObject + { + void generate(CodeVisitor mw) + { + mw.visitInsn(ACONST_NULL); + } + + Object getLiteral() + { + return null; + } + + /** + * Stack effect of executing this -- only used for lists + * and conditionals! + */ + public StackEffect getStackEffect(Set recursiveCheck) + { + return new StackEffect(0,0,0,0); + } + + /** + * Write code for evaluating this. Returns maximum JVM stack + * usage. + */ + public int compileCallTo(CodeVisitor mw, Set recursiveCheck) + throws Exception + { + return 0; + } + } //}}} + + //{{{ Choice + class Choice extends FlowObject + { + FlowObject cond, t, f; + + Choice(FlowObject cond, FlowObject t, FlowObject f) + { + this.cond = cond; + this.t = t; + this.f = f; + } + + void generate(CodeVisitor mw) + { + // if null jump to F + // T + // jump END + // F: F + // END: ... + Label fl = new Label(); + Label endl = new Label(); + + cond.generate(mw); + mw.visitJumpInsn(IFNULL,fl); + t.generate(mw); + mw.visitJumpInsn(GOTO,endl); + mw.visitLabel(fl); + f.generate(mw); + mw.visitLabel(endl); + } + + boolean usingLocal(int local) + { + return cond.usingLocal(local) + || t.usingLocal(local) + || f.usingLocal(local); + } + + /** + * Stack effect of executing this -- only used for lists + * and conditionals! + */ + public StackEffect getStackEffect(Set recursiveCheck) + throws Exception + { + FactorDataStack datastackCopy = (FactorDataStack) + datastack.clone(); + FactorCallStack callstackCopy = (FactorCallStack) + callstack.clone(); + + StackEffect te = t.getStackEffect(recursiveCheck); + + datastack = datastackCopy; + callstack = callstackCopy; + + StackEffect fe = f.getStackEffect(recursiveCheck); + + if(te == null || fe == null) + return null; + + // we can only balance out a conditional if + // both sides leave the same amount of elements + // on the stack. + // eg, 1/1 -vs- 2/2 is ok, 3/1 -vs- 4/2 is ok, + // but 1/2 -vs- 2/1 is not. + int balanceTD = te.outD - te.inD; + int balanceTR = te.outR - te.inR; + int balanceFD = fe.outD - fe.inD; + int balanceFR = fe.outR - fe.inR; + if(balanceTD == balanceFD + && balanceTR == balanceFR) + { + // replace results from the f branch with + // dummy values so that subsequent code + // doesn't assume these values always + // result from this + datastack.top -= te.outD; + for(int i = 0; i < te.outD; i++) + { + push(null); + } + callstack.top -= te.outR; + for(int i = 0; i < te.outR; i++) + { + pushR(null); + } + return new StackEffect( + Math.max(te.inD,fe.inD), + Math.max(te.outD,fe.outD), + Math.max(te.inR,fe.inR), + Math.max(te.outR,fe.outR) + ); + } + else + return null; + } + + /** + * Write code for evaluating this. Returns maximum JVM stack + * usage. + */ + public int compileCallTo(CodeVisitor mw, Set recursiveCheck) + throws Exception + { + // if null jump to F + // T + // jump END + // F: F + // END: ... + Label fl = new Label(); + Label endl = new Label(); + + cond.generate(mw); + mw.visitJumpInsn(IFNULL,fl); + + FactorDataStack datastackCopy = (FactorDataStack) + datastack.clone(); + FactorCallStack callstackCopy = (FactorCallStack) + callstack.clone(); + + int maxJVMStack = t.compileCallTo(mw,recursiveCheck); + mw.visitJumpInsn(GOTO,endl); + mw.visitLabel(fl); + + datastack = datastackCopy; + callstack = callstackCopy; + + maxJVMStack = Math.max(f.compileCallTo( + mw,recursiveCheck),maxJVMStack); + mw.visitLabel(endl); + + return Math.max(maxJVMStack,1); + } + } //}}} +} diff --git a/factor/compiler/StackEffect.java b/factor/compiler/StackEffect.java new file mode 100644 index 0000000000..e447957e10 --- /dev/null +++ b/factor/compiler/StackEffect.java @@ -0,0 +1,168 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.compiler; + +import factor.*; +import java.util.*; + +public class StackEffect +{ + public final int inD; + public final int outD; + public final int inR; + public final int outR; + + //{{{ StackEffect constructor + public StackEffect(int inD, int outD, int inR, int outR) + { + this.inD = inD; + this.outD = outD; + this.inR = inR; + this.outR = outR; + } //}}} + + //{{{ getStackEffect() method + public static StackEffect getStackEffect(Cons definition) + throws Exception + { + return getStackEffect(definition,new HashSet(), + new LocalAllocator()); + } //}}} + + //{{{ getStackEffect() method + public static StackEffect getStackEffect(Cons definition, + Set recursiveCheck, LocalAllocator state) + throws Exception + { + int inD = 0; + int outD = 0; + int inR = 0; + int outR = 0; + + Cons iter = definition; + while(iter != null) + { + Object obj = iter.car; + if(obj instanceof FactorWord) + { + StackEffect se = ((FactorWord)obj).def + .getStackEffect( + recursiveCheck, + state); + + if(se == null) + return null; + + if(se.inD <= outD) + outD -= se.inD; + else + { + inD += (se.inD - outD); + outD = 0; + } + + if(se.inR <= outR) + outR -= se.inR; + else + { + inR += (se.inR - outR); + outR = 0; + } + + outD += se.outD; + outR += se.outR; + } + else + { + outD++; + state.pushLiteral(obj); + } + + iter = iter.next(); + } + + return new StackEffect(inD,outD,inR,outR); + } //}}} + + //{{{ getCorePrototype() method + public String getCorePrototype() + { + StringBuffer signatureBuf = new StringBuffer( + "(Lfactor/FactorInterpreter;"); + + for(int i = 0; i < inD; i++) + { + signatureBuf.append("Ljava/lang/Object;"); + } + + if(outD == 0) + signatureBuf.append(")V"); + else + signatureBuf.append(")Ljava/lang/Object;"); + + return signatureBuf.toString(); + } //}}} + + //{{{ equals() method + public boolean equals(Object o) + { + if(!(o instanceof StackEffect)) + return false; + StackEffect effect = (StackEffect)o; + return effect.inD == inD + && effect.outD == outD + && effect.inR == inR + && effect.outR == outR; + } //}}} + + //{{{ toString() method + public String toString() + { + StringBuffer buf = new StringBuffer(); + for(int i = 0; i < inD; i++) + { + buf.append("I "); + } + for(int i = 0; i < inR; i++) + { + buf.append("r:I "); + } + buf.append("--"); + for(int i = 0; i < outD; i++) + { + buf.append(" O"); + } + for(int i = 0; i < outR; i++) + { + buf.append(" r:O"); + } + return buf.toString(); + } //}}} +} diff --git a/factor/dictionary.factor b/factor/dictionary.factor index 35ed791e29..c4efe64c64 100644 --- a/factor/dictionary.factor +++ b/factor/dictionary.factor @@ -25,43 +25,75 @@ ! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -! Undefined words's def field is equal to this. -"factor.FactorMissingDefinition" "INSTANCE" jfield jvarStatic$ @undefinedWord - -: asm. (word -- assembly) +: asm ( word -- assembly ) ! Prints JVM bytecode disassembly of the given word. - worddef [ $asm ] bind dup [ + worddef compiled? dup [ print ] [ drop "Not a compiled word." print ] ifte ; -: word? (obj -- boolean) - "factor.FactorWord" is ; +: compile* ( word -- ) + $interpreter swap + [ "factor.FactorInterpreter" ] "factor.FactorWord" "compile" + jinvoke ; -: str>word ("word" -- word) - ! Returns the top of the stack if it already been interned. - dup word? [ - $dict [ "java.lang.String" ] "factor.FactorDictionary" "intern" - jmethod jinvoke - ] unless ; +: compile ( word -- ) + dup worddef compiled? [ + drop + ] [ + intern compile* + ] ifte ; -: worddef? (obj -- boolean) - "factor.FactorWordDefinition" is ; +: compileAll ( -- ) + "Compiling..." write + words [ compile ] each + " done" print ; + +: compiled? ( obj -- boolean ) + [ $asm ] bind ; : compound? (obj -- boolean) "factor.FactorCompoundDefinition" is ; +: missing>f ( word -- word/f ) + ! Is it the missing word placeholder? Then push f. + dup undefined? [ drop f ] when ; + : shuffle? (obj -- boolean) "factor.FactorShuffleDefinition" is ; -: worddef (word -- worddef) - str>word - ! Get the 'def' field - "factor.FactorWord" "def" jfield jvar$ - ! Is it equal to the missing word placeholder? Then push f. - dup $undefinedWord = [ drop f ] when ; +: intern ("word" -- word) + ! Returns the top of the stack if it already been interned. + dup word? [ + $dict [ "java.lang.String" ] + "factor.FactorDictionary" "intern" + jinvoke + ] unless ; + +: undefined? ( obj -- boolean ) + "factor.FactorMissingDefinition" is ; + +: word? (obj -- boolean) + "factor.FactorWord" is ; + +: word ( -- word ) + ! Pushes most recently defined word. + $dict "factor.FactorDictionary" "last" jvar$ ; + +: worddef? (obj -- boolean) + "factor.FactorWordDefinition" is ; + +: worddef ( word -- worddef ) + intern + "factor.FactorWord" "def" jvar$ + missing>f ; + +: worddefUncompiled ( word -- worddef ) + intern + "factor.FactorWord" "uncompiled" jvar$ + missing>f ; : words (-- list) ! Pushes a list of all defined words. - $dict [ ] "factor.FactorDictionary" "toWordList" jmethod jinvoke ; + $dict [ ] "factor.FactorDictionary" "toWordList" jinvoke ; diff --git a/factor/examples/httpd.factor b/factor/examples/httpd.factor index 60fca65b53..243c8642a4 100644 --- a/factor/examples/httpd.factor +++ b/factor/examples/httpd.factor @@ -40,7 +40,7 @@ ! - implement an LSP that does an "apropos" search : httpdGetPath ( request -- file ) - dup ".*\\.\\.*" matches [ + dup ".*\\.\\.*" re-matches [ f ] [ dup [ "GET (.*?)( HTTP.*|)" groups dup [ car ] when ] when @@ -58,12 +58,12 @@ : httpdFiletype (filename -- mime-type) [ - [ dup ".*\.gif" matches ] [ drop "image/gif" ] - [ dup ".*\.png" matches ] [ drop "image/png" ] - [ dup ".*\.html" matches ] [ drop "text/html" ] - [ dup ".*\.txt" matches ] [ drop "text/plain" ] - [ dup ".*\.lsd" matches ] [ drop "text/plain" ] - [ t ] [ drop "application/octet-stream" ] + [ ".*\.gif" re-matches ] [ drop "image/gif" ] + [ ".*\.png" re-matches ] [ drop "image/png" ] + [ ".*\.html" re-matches ] [ drop "text/html" ] + [ ".*\.txt" re-matches ] [ drop "text/plain" ] + [ ".*\.lsd" re-matches ] [ drop "text/plain" ] + [ t ] [ drop "application/octet-stream" ] ] cond ; : httpdUriToPath (uri -- path) @@ -123,7 +123,7 @@ dup directory? [ httpdServeDirectory ] [ - dup ".*\.lhtml" matches [ + dup ".*\.lhtml" re-matches [ httpdServeScript ] [ httpdServeFile diff --git a/factor/interpreter.factor b/factor/interpreter.factor index a847cc4f00..cb5787c7b5 100644 --- a/factor/interpreter.factor +++ b/factor/interpreter.factor @@ -29,13 +29,13 @@ "java.lang.Throwable" is ; : printStackTrace (exception --) - [ ] "java.lang.Throwable" "printStackTrace" jmethod jinvoke ; + [ ] "java.lang.Throwable" "printStackTrace" jinvoke ; : exception. (exception --) ! If this is an Factor exception, just print the message, otherwise print ! the entire exception as a string. dup "factor.FactorException" is [ - [ ] "java.lang.Throwable" "getMessage" jmethod jinvoke + [ ] "java.lang.Throwable" "getMessage" jinvoke ] [ >str ] ifte print ; @@ -53,6 +53,7 @@ ":g continues execution (but expect another error)." print "" print "ERROR: " write exception. + :w callstack$ @errorCallStack [ @errorContinuation @@ -131,9 +132,11 @@ words [ . ] each ; : see (word --) - dup worddef [ + dup worddefUncompiled [ (word -- worddef word) - dup [ worddef dup shuffle? "~<< " ": " ? write ] dip + dup [ + worddefUncompiled dup shuffle? "~<< " ": " ? write + ] dip (worddef word -- worddef) write "\n " write @@ -153,6 +156,22 @@ ! Prints the contents of the data stack datastack$ . ; +: stats ( -- ) + "Cons: " write + "factor.Cons" "COUNT" jvar-static$ . + "Words: " write + words length . + "Compiled: " write + words [ worddef compiled? ] subset length . ; + +: gc ( -- ) + [ ] "java.lang.System" "gc" jinvoke-static ; + +: balance ( code -- effect ) + ! Push stack effect of the given code quotation. + [ "factor.Cons" ] "factor.compiler.StackEffect" + "getStackEffect" jinvoke-static ; + : help "" print "= Dynamic, interpreted, stack-based scripting language" print diff --git a/factor/lists.factor b/factor/lists.factor index 3a272a2b50..654bdd4943 100644 --- a/factor/lists.factor +++ b/factor/lists.factor @@ -2,7 +2,7 @@ ! $Id$ ! -! Copyright (C) 2003 Slava Pestov. +! Copyright (C) 2003, 2004 Slava Pestov. ! ! Redistribution and use in source and binary forms, with or without ! modification, are permitted provided that the following conditions are met: @@ -31,8 +31,8 @@ : 2rlist (a b -- [ b a ]) swap unit cons ; -: append ([ list1 ] [ list2 ] -- [ list1 list2 ]) - swap rappend ; +: append ( [ list1 ] [ list2 ] -- [ list1 list2 ] ) + over [ [ uncons ] dip append cons ] [ nip ] ifte ; : add ([ list1 ] elem -- [ list1 elem ]) unit append ; @@ -42,7 +42,8 @@ dup [ $ swap append ] dip @ ; : array>list ( array -- list ) - [ "[Ljava.lang.Object;" ] "factor.FactorList" "fromArray" jmethod jinvokeStatic ; + [ [ "java.lang.Object" ] ] "factor.Cons" "fromArray" + jinvoke-static ; : add@ (elem variable --) ! Adds the element to the end of the list stored in the given variable. @@ -63,10 +64,10 @@ ] ifte ; : car ([ car , cdr ] -- car) - |factor.FactorList |car jfield jvar$ ; + |factor.Cons |car jvar$ ; : cdr ([ car , cdr ] -- cdr) - |factor.FactorList |cdr jfield jvar$ ; + |factor.Cons |cdr jvar$ ; : caar (list -- caar) car car ; @@ -83,10 +84,10 @@ : cloneList (list -- list) ! Returns a new list where each element is a clone of the elements of ! the given list. - dup [ [ ] "factor.FactorList" "deepClone" jmethod jinvoke ] when ; + dup [ [ ] "factor.Cons" "deepClone" jinvoke ] when ; : cons (car cdr -- [ car , cdr ]) - [ |java.lang.Object |java.lang.Object ] |factor.FactorList jconstructor jnew ; + [ |java.lang.Object |java.lang.Object ] |factor.Cons jnew ; : contains (elem list -- boolean) dup [ @@ -113,9 +114,13 @@ : get (list n -- list[n]) [ cdr ] times car ; -: last (list -- last) +: last* ( list -- last ) + ! Pushes last cons of the list. + [ dup cdr ] [ cdr ] while ; + +: last ( list -- last ) ! Pushes last element of the list. - [ dup cdr ] [ cdr ] while car ; + last* car ; : length (list -- length) 0 swap [ drop succ ] each ; @@ -126,18 +131,27 @@ : list? (list -- boolean) dup pair? [ cdr list? ] [ f ] ifte ; -: pair? (list -- boolean) - |factor.FactorList is ; +: nappend ( [ list1 ] [ list2 ] -- [ list1 list2 ] ) + ! Destructive on list1! + over [ last* rplacd ] when* ; -: rappend ([ list2 ] [ list1 ] -- [ list1 list2 ]) - [ [ |factor.FactorList ] |factor.FactorList |append jmethod jinvoke ] when* ; +: pair? (list -- boolean) + |factor.Cons is ; : reverse (list -- list) [ ] swap [ swons ] each ; +: rplaca ( A [ B , C ] -- [ A , C ] ) + ! Destructive! + "factor.Cons" "car" jvar@ ; + +: rplacd ( A [ B , C ] -- [ B , A ] ) + ! Destructive! + "factor.Cons" "cdr" jvar@ ; + : swons (cdr car -- [ car , cdr ]) swap [ |java.lang.Object |java.lang.Object ] - |factor.FactorList jconstructor jnew ; + |factor.Cons jnew ; : uncons ([ car , cdr ] -- car cdr) dup car swap cdr ; diff --git a/factor/math.factor b/factor/math.factor index 8a833771f7..9ef76bf4ee 100644 --- a/factor/math.factor +++ b/factor/math.factor @@ -35,76 +35,64 @@ "java.lang.Integer" is ; : >fixnum (num -- fixnum) - [ ] "java.lang.Number" "intValue" jmethod jinvoke ; + [ ] "java.lang.Number" "intValue" jinvoke ; : bignum? (obj -- boolean) "java.math.BigInteger" is ; : >bignum (num -- bignum) - [ ] "java.lang.Number" "longValue" jmethod jinvoke - [ "long" ] "java.math.BigInteger" "valueOf" jmethod jinvokeStatic ; + [ ] "java.lang.Number" "longValue" jinvoke + [ "long" ] "java.math.BigInteger" "valueOf" jinvoke-static ; : realnum? (obj -- boolean) dup "java.lang.Float" is swap "java.lang.Double" is or ; : >realnum (num -- realnum) - [ ] "java.lang.Number" "doubleValue" jmethod jinvoke ; + [ ] "java.lang.Number" "doubleValue" jinvoke ; : ratio? (obj -- boolean) "factor.FactorRatio" is ; : + (a b -- a+b) [ "java.lang.Number" "java.lang.Number" ] "factor.FactorMath" "add" - jmethod jinvokeStatic ; + jinvoke-static ; : +@ (num var --) dup [ $ + ] dip @ ; : - (a b -- a-b) [ "java.lang.Number" "java.lang.Number" ] "factor.FactorMath" "subtract" - jmethod jinvokeStatic ; + jinvoke-static ; : -@ (num var --) - dup [ $ -- ] dip @ ; - -: -- (a b -- b-a) - swap - ; - -: --@ (var num --) - [ dup $ - ] dip s@ ; + dup [ $ swap - ] dip @ ; : * (a b -- a*b) [ "java.lang.Number" "java.lang.Number" ] "factor.FactorMath" "multiply" - jmethod jinvokeStatic ; + jinvoke-static ; : *@ (num var --) dup [ $ * ] dip @ ; : / (a b -- a/b) [ "java.lang.Number" "java.lang.Number" ] "factor.FactorMath" "divide" - jmethod jinvokeStatic ; + jinvoke-static ; : /@ (num var --) dup [ $ / ] dip @ ; -: // (a b -- b/a) - swap / ; - -: //@ (num var --) - [ dup $ / ] dip s@ ; - : > (a b -- boolean) - [ "float" "float" ] "factor.FactorMath" "greater" jmethod jinvokeStatic ; + [ "float" "float" ] "factor.FactorMath" "greater" jinvoke-static ; : >= (a b -- boolean) - [ "float" "float" ] "factor.FactorMath" "greaterEqual" jmethod jinvokeStatic ; + [ "float" "float" ] "factor.FactorMath" "greaterEqual" jinvoke-static ; : < (a b -- boolean) - [ "float" "float" ] "factor.FactorMath" "less" jmethod jinvokeStatic ; + [ "float" "float" ] "factor.FactorMath" "less" jinvoke-static ; : <= (a b -- boolean) - [ "float" "float" ] "factor.FactorMath" "lessEqual" jmethod jinvokeStatic ; + [ "float" "float" ] "factor.FactorMath" "lessEqual" jinvoke-static ; : and (a b -- a&b) f ? ; @@ -126,9 +114,15 @@ : not@ (boolean -- boolean) dup $ not s@ ; +: pow ( x y -- x^y ) + [ "double" "double" ] "java.lang.Math" "pow" jinvoke-static ; + : pred (n -- n-1) 1 - ; +: round ( x y -- x^y ) + [ "double" "double" ] "java.lang.Math" "pow" jinvoke-static ; + : succ (n -- nsucc) 1 + ; @@ -139,13 +133,13 @@ t swap ? ; : recip (x -- 1/x) - 1 // ; + 1 swap / ; : sq (x -- x^2) dup * ; : sqrt (x -- sqrt x) - [ "double" ] "java.lang.Math" "sqrt" jmethod jinvokeStatic ; + [ "double" ] "java.lang.Math" "sqrt" jinvoke-static ; : succ@ (var --) dup $ 1 + s@ ; diff --git a/factor/miscellaneous.factor b/factor/miscellaneous.factor index 5c3bf79b88..0ff2bec289 100644 --- a/factor/miscellaneous.factor +++ b/factor/miscellaneous.factor @@ -25,30 +25,28 @@ ! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -: >str (obj -- string) - ! Returns the Java string representation of this object. - [ ] "java.lang.Object" "toString" jmethod jinvoke ; - : = (a b -- boolean) ! Returns true if a = b. [ "java.lang.Object" "java.lang.Object" ] - "factor.FactorLib" "equal" jmethod jinvokeStatic ; + "factor.FactorLib" "equal" jinvoke-static ; : clone (obj -- obj) - [ ] "factor.PublicCloneable" "clone" jmethod jinvoke ; + [ ] "factor.PublicCloneable" "clone" jinvoke ; : cloneArray (obj -- obj) - [ "[Ljava.lang.Object;" ] "factor.FactorLib" "cloneArray" - jmethod jinvokeStatic ; + [ [ "java.lang.Object" ] ] + "factor.FactorLib" "cloneArray" + jinvoke-static ; : deepCloneArray (obj -- obj) - [ "[Ljava.lang.Object;" ] "factor.FactorLib" "deepCloneArray" - jmethod jinvokeStatic ; + [ [ "java.lang.Object" ] ] + "factor.FactorLib" "deepCloneArray" + jinvoke-static ; : is (obj class -- boolean) ! Like "instanceof" in Java. [ "java.lang.Object" ] "java.lang.Class" "isInstance" - jmethod jinvoke ; + jinvoke ; : not= (a b -- boolean) = not ; @@ -57,36 +55,31 @@ ! Returns true if a = c, b = d. swapd = [ = ] dip and ; -: ? (cond obj1 obj2 -- obj) - ! Pushes obj1 if cond is true, obj2 if cond is false. - [ "boolean" "java.lang.Object" "java.lang.Object" ] - "factor.FactorLib" "branch2" jmethod jinvokeStatic ; - : >=< (x y obj1 obj2 obj3 -- obj) ! If x > y, pushes obj1, if x = y, pushes obj2, else obj3. [ "float" "float" "java.lang.Object" "java.lang.Object" "java.lang.Object" ] - "factor.FactorLib" "branch3" jmethod jinvokeStatic ; + "factor.FactorLib" "branch3" jinvoke-static ; : error (msg --) - [ "java.lang.String" ] "factor.FactorLib" "error" jmethod jinvokeStatic ; + [ "java.lang.String" ] "factor.FactorLib" "error" jinvoke-static ; : exit* (code --) - [ |int ] |java.lang.System |exit jmethod jinvokeStatic ; + [ |int ] |java.lang.System |exit jinvoke-static ; : exit (--) 0 exit* ; : millis (-- millis) ! Pushes the current time, in milliseconds. - [ ] |java.lang.System |currentTimeMillis jmethod jinvokeStatic + [ ] |java.lang.System |currentTimeMillis jinvoke-static >bignum ; : stack>list (stack -- list) ! Turns a callstack or datastack object into a list. - [ ] "factor.FactorArrayStack" "toList" jmethod jinvoke ; + [ ] "factor.FactorArrayStack" "toList" jinvoke ; : time (code --) ! Evaluates the given code and prints the time taken to execute it. diff --git a/factor/namespaces.factor b/factor/namespaces.factor index b5c4554cae..d02fedbf52 100644 --- a/factor/namespaces.factor +++ b/factor/namespaces.factor @@ -25,6 +25,9 @@ ! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +: s@ ( variable value -- ) + swap @ ; + : lazy (var [ a ] -- value) ! If the value of the variable is f, set the value to the result of ! evaluating [ a ]. @@ -35,12 +38,12 @@ : (-- namespace) $namespace [ |factor.FactorNamespace ] |factor.FactorNamespace - jconstructor jnew ; + jnew ; : ( object -- namespace ) $namespace swap [ "factor.FactorNamespace" "java.lang.Object" ] - "factor.FactorNamespace" jconstructor jnew ; + "factor.FactorNamespace" jnew ; : extend (object code -- object) ! Used in code like this: @@ -52,12 +55,12 @@ : import (class pairs --) ! Import some static variables from a Java class into the current namespace. - $namespace [ |java.lang.String |factor.FactorList ] + $namespace [ |java.lang.String |factor.Cons ] |factor.FactorNamespace |importVars - jmethod jinvoke ; + jinvoke ; : vars (-- list) - $namespace [ ] |factor.FactorNamespace |toVarList jmethod jinvoke ; + $namespace [ ] |factor.FactorNamespace |toVarList jinvoke ; : uvar? (name --) [ "namespace" "parent" ] contains not ; diff --git a/factor/network.factor b/factor/network.factor index 7d97870fc1..9343ce1727 100644 --- a/factor/network.factor +++ b/factor/network.factor @@ -28,21 +28,21 @@ : ( port -- stream ) ! Starts listening on localhost:port. Returns a stream that you can close ! with fclose. No other stream operations are supported. - [ "int" ] "java.net.ServerSocket" jconstructor jnew + [ "int" ] "java.net.ServerSocket" jnew [ @socket ( -- ) [ - $socket [ ] "java.net.ServerSocket" "close" jmethod jinvoke + $socket [ ] "java.net.ServerSocket" "close" jinvoke ] @fclose ] extend ; : ( socket -- stream ) ! Wraps a socket inside a bytestream. dup - [ [ ] "java.net.Socket" "getInputStream" jmethod jinvoke ] - [ [ ] "java.net.Socket" "getOutputStream" jmethod jinvoke ] + [ [ ] "java.net.Socket" "getInputStream" jinvoke ] + [ [ ] "java.net.Socket" "getOutputStream" jinvoke ] cleave [ @socket @@ -50,11 +50,11 @@ ! We "extend" bytestream's fclose. ( -- ) $fclose [ - $socket [ ] "java.net.Socket" "close" jmethod jinvoke + $socket [ ] "java.net.Socket" "close" jinvoke ] append @fclose ] extend ; : accept ( server -- client ) ! Accept a connection from a server socket. [ $socket ] bind - [ ] "java.net.ServerSocket" "accept" jmethod jinvoke ; + [ ] "java.net.ServerSocket" "accept" jinvoke ; diff --git a/factor/parser.factor b/factor/parser.factor index fdf1f76711..ae9df840f0 100644 --- a/factor/parser.factor +++ b/factor/parser.factor @@ -36,7 +36,7 @@ : unparse (X -- "X") [ |java.lang.Object ] |factor.FactorJava |factorTypeToString - jmethod jinvokeStatic ; + jinvoke-static ; : . (expr --) unparse print ; diff --git a/factor/primitives/Bind.java b/factor/primitives/Bind.java new file mode 100644 index 0000000000..f7d34a214d --- /dev/null +++ b/factor/primitives/Bind.java @@ -0,0 +1,126 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.lang.reflect.*; +import java.util.Set; +import org.objectweb.asm.*; + +public class Bind extends FactorWordDefinition +{ + //{{{ Bind constructor + public Bind(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + Cons code = (Cons)datastack.pop(Cons.class); + Object obj = datastack.pop(); + FactorNamespace ns = FactorJava.toNamespace(obj,interp); + interp.call(word,ns,code); + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws Exception + { + state.ensure(state.datastack,2); + LocalAllocator.FlowObject quot + = (LocalAllocator.FlowObject) + state.datastack.pop(); + state.pop(null); + StackEffect effect = quot.getStackEffect(recursiveCheck); + if(effect != null) + { + // add 2 to inD since we consume the + // quotation and the object + return new StackEffect(effect.inD + 2, + effect.outD, + effect.inR, + effect.outR); + } + else + return null; + } //}}} + + //{{{ compileCallTo() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + */ + public int compileCallTo( + CodeVisitor mw, + LocalAllocator allocator, + Set recursiveCheck) + throws Exception + { + LocalAllocator.FlowObject quot = (LocalAllocator.FlowObject) + allocator.datastack.pop(); + + // store namespace on callstack + mw.visitVarInsn(ALOAD,0); + mw.visitFieldInsn(GETFIELD, + "factor/FactorInterpreter", + "callframe", + "Lfactor/FactorCallFrame;"); + mw.visitInsn(DUP); + mw.visitFieldInsn(GETFIELD, + "factor/FactorCallFrame", + "namespace", + "Lfactor/FactorNamespace;"); + allocator.pushR(mw); + + // set new namespace + mw.visitInsn(DUP); + allocator.pop(mw); + FactorJava.generateFromConversion(mw,FactorNamespace.class); + mw.visitFieldInsn(PUTFIELD, + "factor/FactorCallFrame", + "namespace", + "Lfactor/FactorNamespace;"); + + int maxJVMStack = quot.compileCallTo(mw,recursiveCheck); + + // restore namespace from callstack + allocator.popR(mw); + mw.visitFieldInsn(PUTFIELD, + "factor/FactorCallFrame", + "namespace", + "Lfactor/FactorNamespace;"); + + return maxJVMStack + 3; + } //}}} +} diff --git a/factor/primitives/Call.java b/factor/primitives/Call.java new file mode 100644 index 0000000000..a52249eecc --- /dev/null +++ b/factor/primitives/Call.java @@ -0,0 +1,90 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.lang.reflect.*; +import java.util.Set; +import org.objectweb.asm.*; + +public class Call extends FactorWordDefinition +{ + //{{{ Call constructor + public Call(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + interp.call(word,(Cons)interp.datastack.pop( + Cons.class)); + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws Exception + { + state.ensure(state.datastack,1); + LocalAllocator.FlowObject quot + = (LocalAllocator.FlowObject) + state.datastack.pop(); + StackEffect effect = quot.getStackEffect(recursiveCheck); + if(effect != null) + { + // add 1 to inD since we consume the + // quotation + return new StackEffect(effect.inD + 1, + effect.outD, + effect.inR, + effect.outR); + } + else + return null; + } //}}} + + //{{{ compileCallTo() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + */ + public int compileCallTo( + CodeVisitor mw, + LocalAllocator allocator, + Set recursiveCheck) + throws Exception + { + LocalAllocator.FlowObject quot = (LocalAllocator.FlowObject) + allocator.datastack.pop(); + return quot.compileCallTo(mw,recursiveCheck); + } //}}} +} diff --git a/factor/primitives/CallstackGet.java b/factor/primitives/CallstackGet.java new file mode 100644 index 0000000000..9d7c2b5cb0 --- /dev/null +++ b/factor/primitives/CallstackGet.java @@ -0,0 +1,51 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.util.Set; +import org.objectweb.asm.*; + +public class CallstackGet extends FactorWordDefinition +{ + //{{{ CallstackGet constructor + public CallstackGet(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + interp.datastack.push(interp.callstack.clone()); + } //}}} +} diff --git a/factor/primitives/CallstackSet.java b/factor/primitives/CallstackSet.java new file mode 100644 index 0000000000..e9685a0455 --- /dev/null +++ b/factor/primitives/CallstackSet.java @@ -0,0 +1,52 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.util.Set; + +public class CallstackSet extends FactorWordDefinition +{ + //{{{ CallstackSet constructor + public CallstackSet(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + interp.callstack = (FactorCallStack)((FactorCallStack) + interp.datastack.pop(FactorCallStack.class)) + .clone(); + } //}}} +} diff --git a/factor/primitives/Choice.java b/factor/primitives/Choice.java new file mode 100644 index 0000000000..41e7468779 --- /dev/null +++ b/factor/primitives/Choice.java @@ -0,0 +1,85 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import org.objectweb.asm.*; + +public class Choice extends FactorWordDefinition +{ + //{{{ Choice constructor + public Choice(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + Object f = datastack.pop(); + Object t = datastack.pop(); + Object cond = datastack.pop(); + datastack.push(core(interp,cond,t,f)); + } //}}} + + //{{{ core() method + public static Object core(FactorInterpreter interp, + Object cond, Object t, Object f) throws Exception + { + return FactorJava.toBoolean(cond) ? t : f; + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(java.util.Set recursiveCheck, + LocalAllocator state) throws FactorStackException + { + state.ensure(state.datastack,3); + state.pushChoice(); + return new StackEffect(3,1,0,0); + } //}}} + + //{{{ compileCallTo() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + */ + /* public int compileCallTo( + CodeVisitor mw, + LocalAllocator allocator, + java.util.Set recursiveCheck) + throws Exception + { + allocator.pushChoice(); + + return 0; + } */ //}}} +} diff --git a/factor/primitives/Clear.java b/factor/primitives/Clear.java new file mode 100644 index 0000000000..4ce20906eb --- /dev/null +++ b/factor/primitives/Clear.java @@ -0,0 +1,50 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.util.Set; + +public class Clear extends FactorWordDefinition +{ + //{{{ Clear constructor + public Clear(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + interp.datastack.top = 0; + } //}}} +} diff --git a/factor/primitives/DatastackGet.java b/factor/primitives/DatastackGet.java new file mode 100644 index 0000000000..a0c3c25165 --- /dev/null +++ b/factor/primitives/DatastackGet.java @@ -0,0 +1,50 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.util.Set; + +public class DatastackGet extends FactorWordDefinition +{ + //{{{ DatastackGet constructor + public DatastackGet(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + interp.datastack.push(interp.datastack.clone()); + } //}}} +} diff --git a/factor/primitives/DatastackSet.java b/factor/primitives/DatastackSet.java new file mode 100644 index 0000000000..6521842f64 --- /dev/null +++ b/factor/primitives/DatastackSet.java @@ -0,0 +1,52 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.util.Set; + +public class DatastackSet extends FactorWordDefinition +{ + //{{{ DatastackSet constructor + public DatastackSet(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + interp.datastack = (FactorDataStack)((FactorDataStack) + interp.datastack.pop(FactorDataStack.class)) + .clone(); + } //}}} +} diff --git a/factor/primitives/Define.java b/factor/primitives/Define.java new file mode 100644 index 0000000000..c12126e685 --- /dev/null +++ b/factor/primitives/Define.java @@ -0,0 +1,77 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.util.Set; + +public class Define extends FactorWordDefinition +{ + //{{{ Define constructor + public Define(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + FactorDictionary dict = interp.dict; + // handle old define syntax + Object obj = datastack.pop(); + + FactorWord newWord = interp.dict.intern( + (String)datastack.pop(String.class)); + + if(obj instanceof Cons) + { + obj = new FactorCompoundDefinition( + newWord,(Cons)obj); + } + + FactorWordDefinition def = (FactorWordDefinition)obj; + + newWord.define(def); + dict.last = newWord; + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws FactorStackException + { + state.ensure(state.datastack,2); + state.pop(null); + state.pop(null); + return new StackEffect(2,0,0,0); + } //}}} +} diff --git a/factor/primitives/Get.java b/factor/primitives/Get.java new file mode 100644 index 0000000000..868d4d148e --- /dev/null +++ b/factor/primitives/Get.java @@ -0,0 +1,69 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.util.Set; + +public class Get extends FactorWordDefinition +{ + //{{{ Get constructor + public Get(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + datastack.push(core(interp,datastack.pop())); + } //}}} + + //{{{ core() method + public static Object core(FactorInterpreter interp, + Object name) throws Exception + { + return interp.callframe.namespace.getVariable( + FactorJava.toString(name)); + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws FactorStackException + { + state.ensure(state.datastack,1); + state.pop(null); + state.push(null); + return new StackEffect(1,1,0,0); + } //}}} +} diff --git a/factor/primitives/JInvoke.java b/factor/primitives/JInvoke.java new file mode 100644 index 0000000000..0612543689 --- /dev/null +++ b/factor/primitives/JInvoke.java @@ -0,0 +1,146 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.lang.reflect.*; +import java.util.Set; +import org.objectweb.asm.*; + +public class JInvoke extends FactorWordDefinition +{ + //{{{ JInvoke constructor + public JInvoke(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + Method method = FactorJava.jmethod( + (String)datastack.pop(String.class), + (String)datastack.pop(String.class), + (Cons)datastack.pop(Cons.class)); + FactorJava.jinvoke(datastack, + method,datastack.pop()); + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws Exception + { + state.ensure(state.datastack,4); + Object clazz = state.popLiteral(); + Object name = state.popLiteral(); + Object args = state.popLiteral(); + state.pop(null); + + if(clazz instanceof String && + name instanceof String && + (args == null || args instanceof Cons)) + { + Method method = FactorJava.jmethod( + (String)clazz, + (String)name, + (Cons)args); + + boolean returnValue = method.getReturnType() == Void.TYPE; + if(returnValue) + state.push(null); + return new StackEffect( + 4 + method.getParameterTypes().length, + returnValue ? 0 : 1,0,0); + } + else + return null; + } //}}} + + //{{{ compileCallTo() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + * XXX: does not use factor type system conversions. + */ + public int compileCallTo( + CodeVisitor mw, + LocalAllocator allocator, + Set recursiveCheck) + throws Exception + { + Object _method = allocator.popLiteral(); + Object _clazz = allocator.popLiteral(); + Object _args = allocator.popLiteral(); + if(_method instanceof String && + _clazz instanceof String && + (_args == null || _args instanceof Cons)) + { + String method = (String)_method; + String clazz = (String)_clazz; + Class[] args = FactorJava.classNameToClassList( + (Cons)_args); + Class cls = FactorJava.getClass(clazz); + Method mth = cls.getMethod(method,args); + Class returnType = mth.getReturnType(); + + clazz = clazz.replace('.','/'); + + FactorJava.generateToConversionPre(mw,returnType); + + allocator.pop(mw); + FactorJava.generateFromConversion(mw,cls); + + allocator.generateArgs(mw,args.length,args); + + int opcode; + if(cls.isInterface()) + opcode = INVOKEINTERFACE; + else + opcode = INVOKEVIRTUAL; + mw.visitMethodInsn(opcode, + clazz, + method, + FactorJava.javaSignatureToVMSignature( + args,returnType)); + + if(returnType != Void.TYPE) + { + FactorJava.generateToConversion(mw,returnType); + allocator.push(mw); + } + + return 4 + args.length; + } + else + throw new FactorCompilerException("Cannot compile jinvoke with non-literal parameters"); + } //}}} +} diff --git a/factor/primitives/JInvokeStatic.java b/factor/primitives/JInvokeStatic.java new file mode 100644 index 0000000000..376ec8ea2e --- /dev/null +++ b/factor/primitives/JInvokeStatic.java @@ -0,0 +1,136 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.lang.reflect.*; +import java.util.Set; +import org.objectweb.asm.*; + +public class JInvokeStatic extends FactorWordDefinition +{ + //{{{ JInvokeStatic constructor + public JInvokeStatic(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + Method method = FactorJava.jmethod( + (String)datastack.pop(String.class), + (String)datastack.pop(String.class), + (Cons)datastack.pop(Cons.class)); + FactorJava.jinvokeStatic(datastack,method); + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws Exception + { + state.ensure(state.datastack,3); + Object clazz = state.popLiteral(); + Object name = state.popLiteral(); + Object args = state.popLiteral(); + + if(clazz instanceof String && + name instanceof String && + (args == null || args instanceof Cons)) + { + Method method = FactorJava.jmethod( + (String)clazz, + (String)name, + (Cons)args); + + boolean returnValue = method.getReturnType() == Void.TYPE; + if(returnValue) + state.push(null); + return new StackEffect( + 3 + method.getParameterTypes().length, + returnValue ? 0 : 1,0,0); + } + else + return null; + } //}}} + + //{{{ compileCallTo() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + * XXX: does not use factor type system conversions. + */ + public int compileCallTo( + CodeVisitor mw, + LocalAllocator allocator, + Set recursiveCheck) + throws Exception + { + Object _method = allocator.popLiteral(); + Object _clazz = allocator.popLiteral(); + Object _args = allocator.popLiteral(); + if(_method instanceof String && + _clazz instanceof String && + (_args == null || _args instanceof Cons)) + { + String method = (String)_method; + String clazz = (String)_clazz; + Class[] args = FactorJava.classNameToClassList( + (Cons)_args); + Class cls = FactorJava.getClass(clazz); + Method mth = cls.getMethod(method,args); + Class returnType = mth.getReturnType(); + + clazz = clazz.replace('.','/'); + + FactorJava.generateToConversionPre(mw,returnType); + + allocator.generateArgs(mw,args.length,args); + + mw.visitMethodInsn(INVOKESTATIC, + clazz, + method, + FactorJava.javaSignatureToVMSignature( + args,returnType)); + + if(returnType != Void.TYPE) + { + FactorJava.generateToConversion(mw,returnType); + allocator.push(mw); + } + + return 4 + args.length; + } + else + throw new FactorCompilerException("Cannot compile jinvoke with non-literal parameters"); + } //}}} +} diff --git a/factor/primitives/JNew.java b/factor/primitives/JNew.java new file mode 100644 index 0000000000..c5b6c0421f --- /dev/null +++ b/factor/primitives/JNew.java @@ -0,0 +1,125 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.lang.reflect.*; +import java.util.Set; +import org.objectweb.asm.*; + +public class JNew extends FactorWordDefinition +{ + //{{{ JNew constructor + public JNew(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + String name = (String)datastack.pop(String.class); + Cons args = (Cons)datastack.pop(Cons.class); + Constructor constructor = FactorJava.jconstructor( + name,args); + FactorJava.jnew(datastack,constructor); + } //}}} + + //{{{ getStackEffect() method + /** + * XXX: does not use factor type system conversions. + */ + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws Exception + { + state.ensure(state.datastack,2); + + Object clazz = state.popLiteral(); + Object args = state.popLiteral(); + if(clazz instanceof String && + (args == null || args instanceof Cons)) + { + Constructor constructor + = FactorJava.jconstructor( + (String)clazz, + (Cons)args); + + state.push(null); + return new StackEffect( + 2 + constructor.getParameterTypes() + .length,1,0,0); + } + else + return null; + } //}}} + + //{{{ compileCallTo() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + * XXX: does not use factor type system conversions. + */ + public int compileCallTo( + CodeVisitor mw, + LocalAllocator allocator, + Set recursiveCheck) + throws Exception + { + Object _clazz = allocator.popLiteral(); + Object _args = allocator.popLiteral(); + if(_clazz instanceof String && + (_args == null || _args instanceof Cons)) + { + String clazz = ((String)_clazz) + .replace('.','/'); + Class[] args = FactorJava.classNameToClassList( + (Cons)_args); + + mw.visitTypeInsn(NEW,clazz); + mw.visitInsn(DUP); + + allocator.generateArgs(mw,args.length,args); + + mw.visitMethodInsn(INVOKESPECIAL, + clazz, + "", + FactorJava.javaSignatureToVMSignature( + args,void.class)); + + allocator.push(mw); + + return 3 + args.length; + } + else + throw new FactorCompilerException("Cannot compile jnew with non-literal parameters"); + } //}}} +} diff --git a/factor/primitives/JVarGet.java b/factor/primitives/JVarGet.java new file mode 100644 index 0000000000..7bcf82ce1d --- /dev/null +++ b/factor/primitives/JVarGet.java @@ -0,0 +1,110 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.lang.reflect.*; +import java.util.Set; +import org.objectweb.asm.*; + +public class JVarGet extends FactorWordDefinition +{ + //{{{ JVarGet constructor + public JVarGet(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + Field field = FactorJava.jfield( + (String)datastack.pop(String.class), + (String)datastack.pop(String.class)); + datastack.push( + FactorJava.jvarGet( + field,datastack.pop())); + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws FactorStackException + { + state.ensure(state.datastack,3); + state.pop(null); + state.pop(null); + state.pop(null); + state.push(null); + return new StackEffect(3,1,0,0); + } //}}} + + //{{{ compileCallTo() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + * XXX: does not use factor type system conversions. + */ + public int compileCallTo( + CodeVisitor mw, + LocalAllocator allocator, + Set recursiveCheck) + throws Exception + { + Object _field = allocator.popLiteral(); + Object _clazz = allocator.popLiteral(); + if(_clazz instanceof String && + _field instanceof String) + { + String field = (String)_field; + String clazz = (String)_clazz; + Class cls = FactorJava.getClass(clazz); + clazz = clazz.replace('.','/'); + Field fld = cls.getField(field); + + FactorJava.generateToConversionPre(mw,fld.getType()); + + allocator.pop(mw); + FactorJava.generateFromConversion(mw,cls); + + mw.visitFieldInsn(GETFIELD,clazz,field, + FactorJava.javaClassToVMClass(fld.getType())); + + FactorJava.generateToConversion(mw,fld.getType()); + + allocator.push(mw); + + return 2; + } + else + throw new FactorCompilerException("Cannot compile jvar$ with non-literal parameters"); + } //}}} +} diff --git a/factor/primitives/JVarGetStatic.java b/factor/primitives/JVarGetStatic.java new file mode 100644 index 0000000000..2d1113242f --- /dev/null +++ b/factor/primitives/JVarGetStatic.java @@ -0,0 +1,105 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.lang.reflect.*; +import java.util.Set; +import org.objectweb.asm.*; + +public class JVarGetStatic extends FactorWordDefinition +{ + //{{{ JVarGetStatic constructor + public JVarGetStatic(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + Field field = FactorJava.jfield( + (String)datastack.pop(String.class), + (String)datastack.pop(String.class)); + datastack.push( + FactorJava.jvarGetStatic(field)); + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws FactorStackException + { + state.ensure(state.datastack,2); + state.pop(null); + state.pop(null); + state.push(null); + return new StackEffect(2,1,0,0); + } //}}} + + //{{{ compileCallTo() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + * XXX: does not use factor type system conversions. + */ + public int compileCallTo( + CodeVisitor mw, + LocalAllocator allocator, + Set recursiveCheck) + throws Exception + { + Object _field = allocator.popLiteral(); + Object _clazz = allocator.popLiteral(); + if(_clazz instanceof String && + _field instanceof String) + { + String field = (String)_field; + String clazz = (String)_clazz; + Class cls = FactorJava.getClass(clazz); + clazz = clazz.replace('.','/'); + Field fld = cls.getField(field); + + FactorJava.generateToConversionPre(mw,fld.getType()); + + mw.visitFieldInsn(GETSTATIC,clazz,field, + FactorJava.javaClassToVMClass(fld.getType())); + + FactorJava.generateToConversion(mw,fld.getType()); + + allocator.push(mw); + + return 2; + } + else + throw new FactorCompilerException("Cannot compile jvar-static$ with non-literal parameters"); + } //}}} +} diff --git a/factor/primitives/JVarSet.java b/factor/primitives/JVarSet.java new file mode 100644 index 0000000000..7b75ca112a --- /dev/null +++ b/factor/primitives/JVarSet.java @@ -0,0 +1,110 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.lang.reflect.*; +import java.util.Set; +import org.objectweb.asm.*; + +public class JVarSet extends FactorWordDefinition +{ + //{{{ JVarSet constructor + public JVarSet(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + Field field = FactorJava.jfield( + (String)datastack.pop(String.class), + (String)datastack.pop(String.class)); + FactorJava.jvarSet( + field, + datastack.pop(), + datastack.pop()); + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws FactorStackException + { + state.ensure(state.datastack,4); + state.pop(null); + state.pop(null); + state.pop(null); + state.pop(null); + return new StackEffect(4,0,0,0); + } //}}} + + //{{{ compileCallTo() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + * XXX: does not use factor type system conversions. + */ + public int compileCallTo( + CodeVisitor mw, + LocalAllocator allocator, + Set recursiveCheck) + throws Exception + { + Object _field = allocator.popLiteral(); + Object _clazz = allocator.popLiteral(); + if(_clazz instanceof String && + _field instanceof String) + { + String field = (String)_field; + String clazz = (String)_clazz; + Class cls = FactorJava.getClass(clazz); + clazz = clazz.replace('.','/'); + Field fld = cls.getField(field); + + allocator.pop(mw); + FactorJava.generateFromConversion(mw,cls); + + allocator.pop(mw); + FactorJava.generateFromConversion(mw,fld.getType()); + + mw.visitFieldInsn(PUTFIELD, + clazz, + field, + FactorJava.javaClassToVMClass(fld.getType())); + + return 2; + } + else + throw new FactorCompilerException("Cannot compile jvar@ with non-literal parameters"); + } //}}} +} diff --git a/factor/primitives/JVarSetStatic.java b/factor/primitives/JVarSetStatic.java new file mode 100644 index 0000000000..ad68057492 --- /dev/null +++ b/factor/primitives/JVarSetStatic.java @@ -0,0 +1,104 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.lang.reflect.*; +import java.util.Set; +import org.objectweb.asm.*; + +public class JVarSetStatic extends FactorWordDefinition +{ + //{{{ JVarSetStatic constructor + public JVarSetStatic(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + Field field = FactorJava.jfield( + (String)datastack.pop(String.class), + (String)datastack.pop(String.class)); + FactorJava.jvarSetStatic( + field,datastack.pop()); + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(Set recursiveCheck, + LocalAllocator state) throws FactorStackException + { + state.ensure(state.datastack,3); + state.pop(null); + state.pop(null); + state.pop(null); + return new StackEffect(3,0,0,0); + } //}}} + + //{{{ compileCallTo() method + /** + * Compile a call to this word. Returns maximum JVM stack use. + * XXX: does not use factor type system conversions. + */ + public int compileCallTo( + CodeVisitor mw, + LocalAllocator allocator, + Set recursiveCheck) + throws Exception + { + Object _field = allocator.popLiteral(); + Object _clazz = allocator.popLiteral(); + if(_clazz instanceof String && + _field instanceof String) + { + String field = (String)_field; + String clazz = (String)_clazz; + Class cls = FactorJava.getClass(clazz); + clazz = clazz.replace('.','/'); + Field fld = cls.getField(field); + + allocator.pop(mw); + FactorJava.generateFromConversion(mw,fld.getType()); + + mw.visitFieldInsn(PUTSTATIC, + clazz, + field, + FactorJava.javaClassToVMClass(fld.getType())); + + return 2; + } + else + throw new FactorCompilerException("Cannot compile jvar-static@ with non-literal parameters"); + } //}}} +} diff --git a/factor/primitives/Restack.java b/factor/primitives/Restack.java new file mode 100644 index 0000000000..346b06393c --- /dev/null +++ b/factor/primitives/Restack.java @@ -0,0 +1,53 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.util.Set; + +public class Restack extends FactorWordDefinition +{ + //{{{ Restack constructor + public Restack(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + Cons list = (Cons)datastack.pop(Cons.class); + interp.callstack.push(datastack); + interp.datastack = new FactorDataStack(list); + } //}}} +} diff --git a/factor/primitives/Set.java b/factor/primitives/Set.java new file mode 100644 index 0000000000..9a58151394 --- /dev/null +++ b/factor/primitives/Set.java @@ -0,0 +1,70 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; + +public class Set extends FactorWordDefinition +{ + //{{{ Set constructor + public Set(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + FactorDataStack datastack = interp.datastack; + Object name = datastack.pop(); + Object value = datastack.pop(); + core(interp,value,name); + } //}}} + + //{{{ core() method + public static void core(FactorInterpreter interp, + Object value, Object name) throws Exception + { + interp.callframe.namespace.setVariable( + FactorJava.toString(name),value); + } //}}} + + //{{{ getStackEffect() method + public StackEffect getStackEffect(java.util.Set recursiveCheck, + LocalAllocator state) throws FactorStackException + { + state.ensure(state.datastack,2); + state.pop(null); + state.pop(null); + return new StackEffect(2,0,0,0); + } //}}} +} diff --git a/factor/primitives/Unstack.java b/factor/primitives/Unstack.java new file mode 100644 index 0000000000..4986620ddc --- /dev/null +++ b/factor/primitives/Unstack.java @@ -0,0 +1,52 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.util.Set; + +public class Unstack extends FactorWordDefinition +{ + //{{{ Unstack constructor + public Unstack(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + Cons unstack = interp.datastack.toList(); + interp.datastack = (FactorDataStack)interp.callstack.pop(); + interp.datastack.push(unstack); + } //}}} +} diff --git a/factor/primitives/Unwind.java b/factor/primitives/Unwind.java new file mode 100644 index 0000000000..02ee87a919 --- /dev/null +++ b/factor/primitives/Unwind.java @@ -0,0 +1,50 @@ +/* :folding=explicit:collapseFolds=1: */ + +/* + * $Id$ + * + * Copyright (C) 2003, 2004 Slava Pestov. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package factor.primitives; + +import factor.compiler.*; +import factor.*; +import java.util.Set; + +public class Unwind extends FactorWordDefinition +{ + //{{{ Unwind constructor + public Unwind(FactorWord word) + { + super(word); + } //}}} + + //{{{ eval() method + public void eval(FactorInterpreter interp) + throws Exception + { + interp.callstack.top = 0; + } //}}} +} diff --git a/factor/random.factor b/factor/random.factor index 1c8afd29b9..294ee077a9 100644 --- a/factor/random.factor +++ b/factor/random.factor @@ -2,7 +2,7 @@ ! $Id$ ! -! Copyright (C) 2003 Slava Pestov. +! Copyright (C) 2003, 2004 Slava Pestov. ! ! Redistribution and use in source and binary forms, with or without ! modification, are permitted provided that the following conditions are met: @@ -25,64 +25,76 @@ ! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -: randomAngle (-- theta) - [ ] "factor.FactorMath" "randomAngle" jmethod jinvokeStatic ; +: random-angle ( -- theta ) + [ ] "factor.FactorMath" + "randomAngle" jinvoke-static ; -: randomBoolean (-- boolean) - [ ] "factor.FactorMath" "randomBoolean" jmethod jinvokeStatic ; +: random-boolean ( -- boolean ) + [ ] "factor.FactorMath" + "randomBoolean" jinvoke-static ; -: randomInt (min max -- random) - [ "int" "int" ] "factor.FactorMath" "randomInt" jmethod jinvokeStatic ; +: random-digit ( -- digit ) + 0 9 random-int ; -: randomSymmetricInt (max -- random) +: random-float ( min max scale -- random ) + [ "int" "int" "float" ] "factor.FactorMath" + "randomFloat" jinvoke-static ; + +: random-int ( min max -- random ) + [ "int" "int" ] "factor.FactorMath" + "randomInt" jinvoke-static ; + +: random-symmetric-int ( max -- random ) ! Return a random integer between -max and max. - dup neg swap randomInt ; + dup neg swap random-int ; -: chance (n -- boolean) - ! Returns true with a 1/n probability, false with a (n-1)/n probability. - 1 swap randomInt 1 = ; - -: randomElement (list -- random) - ! Returns a random element from the given list. - dup length pred 0 swap randomInt get ; - -: randomSubset (list -- list) - ! Returns a random subset of the given list. Each item is chosen with a 50% +: chance ( n -- boolean ) + ! Returns true with a 1/n probability, false with a (n-1)/n ! probability. - [ ] [ randomBoolean [ drop ] when ] map ; + 1 swap random-int 1 = ; -: car+ (list -- sum) +: random-element ( list -- random ) + ! Returns a random element from the given list. + dup length pred 0 swap random-int get ; + +: random-subset ( list -- list ) + ! Returns a random subset of the given list. Each item is + ! chosen with a 50% + ! probability. + [ random-boolean [ drop ] when ] map ; + +: car+ ( list -- sum ) ! Adds the car of each element of the given list. 0 swap [ car + ] each ; -: randomProbability (list -- sum) - ! Adds the car of each element of the given list, and returns a random - ! number between 1 and this sum. - 1 swap car+ randomInt ; +: random-probability ( list -- sum ) + ! Adds the car of each element of the given list, and + ! returns a random number between 1 and this sum. + 1 swap car+ random-int ; -: randomElementIter (list index -- elem) - ! Used by randomElement*. Do not call directly. +: random-element-iter ( list index -- elem ) + ! Used by random-element*. Do not call directly. [ unswons unswons ] dip (list elem probability index) - -- (list elem index) + swap - (list elem index) dup 0 <= [ drop nip ] [ - nip randomElementIter + nip random-element-iter ] ifte ; -: randomElement* (list -- elem) - ! Returns a random element of the given list of comma pairs. The - ! car of each pair is a probability, the cdr is the item itself. - ! Only the cdr of the comma pair is returned. - dup 1 swap car+ randomInt randomElementIter ; +: random-element* ( list -- elem ) + ! Returns a random element of the given list of comma pairs. + ! The car of each pair is a probability, the cdr is the item + ! itself. Only the cdr of the comma pair is returned. + dup 1 swap car+ random-int random-element-iter ; -: randomSubset* (list -- list) - ! Returns a random subset of the given list of comma pairs. The - ! car of each pair is a probability, the cdr is the item itself. - ! Only the cdr of the comma pair is returned. +: random-subset* ( list -- list ) + ! Returns a random subset of the given list of comma pairs. + ! The car of each pair is a probability, the cdr is the item + ! itself. Only the cdr of the comma pair is returned. dup [ [ [ ] ] dip car+ ] dip ([ ] probabilitySum list) [ - [ 1 over randomInt ] dip ([ ] probabilitySum probability elem) + [ 1 over random-int ] dip ([ ] probabilitySum probability elem) uncons ([ ] probabilitySum probability elema elemd) -rot ([ ] probabilitySum elemd probability elema) > ([ ] probabilitySum elemd boolean) diff --git a/factor/stream.factor b/factor/stream.factor index e61a79ff71..7f91733950 100644 --- a/factor/stream.factor +++ b/factor/stream.factor @@ -2,7 +2,7 @@ ! $Id$ ! -! Copyright (C) 2003 Slava Pestov. +! Copyright (C) 2003, 2004 Slava Pestov. ! ! Redistribution and use in source and binary forms, with or without ! modification, are permitted provided that the following conditions are met: @@ -26,18 +26,18 @@ ! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. : ( -- stream ) - ! Create a stream object. A stream is a namespace with the following - ! entries: + ! Create a stream object. A stream is a namespace with the + ! following entries: ! - fflush ! - freadln -- you must provide an implementation! ! - fwriteln ! - fwrite -- you must provide an implementation! ! - fclose - ! Note that you must extend this object and provide your own implementations - ! of all entries except for fwriteln, which is defined to fwrite the string - ! followed by the newline by default. + ! Note that you must extend this object and provide your own + ! implementations of all entries except for fwriteln, which + ! is defined to fwrite the string followed by the newline by + ! default. [ - ( -- string ) [ "freadln not implemented." break ] @freadln ( string -- ) @@ -50,91 +50,99 @@ [ $namespace fwrite "\n" $namespace fwrite ] @fwriteln ] extend ; +! These are in separate words so that they can be compiled. +! Do not call them directly. + +: /freadln ( -- string ) + $in [ "java.io.InputStream" ] "factor.FactorLib" "readLine" + jinvoke-static ; + +: /fwrite ( string -- ) + >bytes + $out [ [ "byte" ] ] + "java.io.OutputStream" "write" jinvoke ; + +: /fflush ( -- ) + $out [ ] "java.io.OutputStream" "flush" jinvoke ; + +: /fclose ( -- ) + $in [ ] "java.io.InputStream" "close" jinvoke + $out [ ] "java.io.OutputStream" "close" jinvoke ; + : ( in out -- stream ) - ! Creates a new stream for reading from the java.io.InputStream in, and - ! writing to the java.io.OutputStream out. + ! Creates a new stream for reading from the + ! java.io.InputStream in, and writing to the + ! java.io.OutputStream out. [ @out @in - ( -- string ) - [ - $in [ "java.io.InputStream" ] "factor.FactorLib" "readLine" - jmethod jinvokeStatic - ] @freadln - + [ /freadln ] @freadln ( string -- ) - [ - >bytes - $out [ "[B" ] "java.io.OutputStream" "write" jmethod jinvoke - ] @fwrite - + [ /fwrite ] @fwrite ( -- ) - [ - $out [ ] "java.io.OutputStream" "flush" jmethod jinvoke - ] @fflush - + [ /fflush ] @fflush ( -- ) - [ - $in [ ] "java.io.InputStream" "close" jmethod jinvoke - $out [ ] "java.io.OutputStream" "close" jmethod jinvoke - ] @fclose + [ /fclose ] @fclose ] extend ; +: /freadln ( -- string ) + $in [ ] "java.io.BufferedReader" "readLine" + jinvoke ; + +: /fwrite ( string -- ) + $out [ "java.lang.String" ] "java.io.Writer" "write" + jinvoke ; + +: /fflush ( -- ) + $out [ ] "java.io.Writer" "flush" jinvoke ; + +: /fclose ( -- ) + $in [ ] "java.io.Reader" "close" jinvoke + $out [ ] "java.io.Writer" "close" jinvoke ; + : ( in out -- stream ) - ! Creates a new stream for reading from the java.io.BufferedReader in, and - ! writing to the java.io.Reader out. + ! Creates a new stream for reading from the + ! java.io.BufferedReader in, and writing to the + ! java.io.Reader out. [ @out @in - ( -- string ) - [ - $in [ ] "java.io.BufferedReader" "readLine" jmethod jinvoke - ] @freadln - + [ /freadln ] @freadln ( string -- ) - [ - $out [ "java.lang.String" ] "java.io.Writer" "write" jmethod jinvoke - ] @fwrite - + [ /fwrite ] @fwrite ( -- ) - [ - $out [ ] "java.io.Writer" "flush" jmethod jinvoke - ] @fflush - + [ /fflush ] @fflush ( -- ) - [ - $in [ ] "java.io.Reader" "close" jmethod jinvoke - $out [ ] "java.io.Writer" "close" jmethod jinvoke - ] @fclose + [ /fclose ] @fclose ] extend ; : ( path -- stream ) - [ |java.lang.String ] |java.io.FileReader jconstructor jnew + [ |java.lang.String ] |java.io.FileReader jnew f ; : ( path -- stream ) f - [ |java.lang.String ] |java.io.FileWriter jconstructor jnew + [ |java.lang.String ] |java.io.FileWriter jnew ; : ( path -- stream ) - [ |java.lang.String ] |java.io.FileInputStream jconstructor jnew + [ |java.lang.String ] |java.io.FileInputStream jnew f ; : ( path -- stream ) f - [ |java.lang.String ] |java.io.FileOutputStream jconstructor jnew + [ |java.lang.String ] |java.io.FileOutputStream jnew ; : (writer -- bwriter) - [ |java.io.Writer ] |java.io.BufferedWriter jconstructor jnew ; + [ |java.io.Writer ] |java.io.BufferedWriter jnew ; : (outputstream -- owriter) - [ |java.io.OutputStream ] |java.io.OutputStreamWriter jconstructor jnew ; + [ |java.io.OutputStream ] |java.io.OutputStreamWriter jnew ; : read ( -- string ) $stdio freadln ; @@ -165,30 +173,30 @@ [ [ $in ] bind ] dip [ $out ] bind [ "java.io.InputStream" "java.io.OutputStream" ] - "factor.FactorLib" "copy" jmethod jinvokeStatic ; + "factor.FactorLib" "copy" jinvoke-static ; -"java.lang.System" "in" jfield jvarStatic$ @stdin -"java.lang.System" "out" jfield jvarStatic$ @stdout +"java.lang.System" "in" jvar-static$ @stdin +"java.lang.System" "out" jvar-static$ @stdout $stdin $stdout @stdio !(file -- freader) | [ - [ |java.lang.String ] |java.io.FileReader jconstructor jnew + [ |java.lang.String ] |java.io.FileReader jnew ] define : (path -- file) dup "java.io.File" is not [ - [ "java.lang.String" ] "java.io.File" jconstructor jnew + [ "java.lang.String" ] "java.io.File" jnew ] when ; : exists? (file -- boolean) - [ ] "java.io.File" "exists" jmethod jinvoke ; + [ ] "java.io.File" "exists" jinvoke ; : directory? (file -- boolean) - [ ] "java.io.File" "isDirectory" jmethod jinvoke ; + [ ] "java.io.File" "isDirectory" jinvoke ; : directory ( file -- listing ) - [ ] "java.io.File" "list" jmethod jinvoke + [ ] "java.io.File" "list" jinvoke array>list ; : rename ( from to -- ) @@ -196,26 +204,27 @@ $stdin $stdout @stdio ! java.io.File instances. swap [ "java.io.File" ] "java.io.File" "renameTo" - jmethod jinvoke ; + jinvoke ; !(string -- reader) | [ - [ |java.lang.String ] |java.io.StringReader jconstructor jnew + [ |java.lang.String ] |java.io.StringReader jnew ] define : close (stream --) - dup "java.io.Reader" is - [ ] "java.io.Reader" "close" jmethod - [ ] "java.io.Writer" "close" jmethod - ? - jinvoke ; + dup "java.io.Reader" is [ + [ ] "java.io.Reader" "close" jinvoke + ] [ + [ ] "java.io.Writer" "close" jinvoke + ] ifte ; -: exec (args -- exitCode) - [ "[Ljava.lang.String;" ] "factor.FactorLib" "exec" jmethod jinvokeStatic ; +: exec ( args -- exitCode ) + [ [ "java.lang.String" ] ] "factor.FactorLib" "exec" + jinvoke-static ; !(stream -- string) |read* [ - [ ] |java.io.BufferedReader |readLine jmethod jinvoke + [ ] |java.io.BufferedReader |readLine jinvoke ] define : print* (string stream --) @@ -225,6 +234,6 @@ $stdin $stdout @stdio !(string stream --) |write* [ tuck - [ |java.lang.String ] |java.io.Writer |write jmethod jinvoke - [ ] |java.io.Writer |flush jmethod jinvoke + [ |java.lang.String ] |java.io.Writer |write jinvoke + [ ] |java.io.Writer |flush jinvoke ] define diff --git a/factor/strings.factor b/factor/strings.factor index ed7bfb7dfe..a88827cee6 100644 --- a/factor/strings.factor +++ b/factor/strings.factor @@ -2,7 +2,7 @@ ! $Id$ ! -! Copyright (C) 2003 Slava Pestov. +! Copyright (C) 2003, 2004 Slava Pestov. ! ! Redistribution and use in source and binary forms, with or without ! modification, are permitted provided that the following conditions are met: @@ -35,103 +35,186 @@ ! [ #\" , """ ] ] @entities +: >str ( obj -- string ) + ! Returns the Java string representation of this object. + [ ] "java.lang.Object" "toString" jinvoke ; + : >bytes ( string -- array ) - ! Converts a string to an array of ASCII bytes. An exception is thrown - ! if the string contains non-ASCII characters. + ! Converts a string to an array of ASCII bytes. An exception + ! is thrown if the string contains non-ASCII characters. "ASCII" swap - [ "java.lang.String" ] "java.lang.String" "getBytes" jmethod jinvoke ; + [ "java.lang.String" ] "java.lang.String" "getBytes" + jinvoke ; -: cat ([ "a" "b" "c" ] -- "abc") - [ "factor.FactorList" ] "factor.FactorLib" "cat" jmethod jinvokeStatic ; +: ( -- StringBuffer ) + [ ] "java.lang.StringBuffer" jnew ; -: cat2 ("a" "b" -- "ab") - [ "java.lang.Object" "java.lang.Object" ] - "factor.FactorLib" "cat2" jmethod jinvokeStatic ; +: sbuf-append ( str buf -- buf ) + [ "java.lang.String" ] "java.lang.StringBuffer" "append" + jinvoke ; -: cat3 ("a" "b" "c" -- "abc") - [ "java.lang.Object" "java.lang.Object" "java.lang.Object" ] - "factor.FactorLib" "cat3" jmethod jinvokeStatic ; +: cat ( [ "a" "b" "c" ] -- "abc" ) + ! If f appears in the list, it is not appended to the + ! string. + swap [ [ swap sbuf-append ] when* ] each >str ; -: cat4 ("a" "b" "c" "d" -- "abcd") - cat2 cat3 ; +: cat2 ( "a" "b" -- "ab" ) + swap sbuf-append sbuf-append >str ; -: chars>entities (str -- str) +: cat3 ( "a" "b" "c" -- "abc" ) + [ ] cons cons cons cat ; + +: cat4 ( "a" "b" "c" "d" -- "abcd" ) + [ ] cons cons cons cons cat ; + +: char? ( obj -- boolean ) + "java.lang.Character" is ; + +: chars>entities ( str -- str ) ! Convert <, >, &, ' and " to HTML entities. - "" [ dup $entities assoc dup [ nip ] [ drop ] ifte ] strmap ; + [ dup $entities assoc dup [ nip ] [ drop ] ifte ] strmap ; -: group (index match --) +: group ( index match -- ) [ "int" ] "java.util.regex.Matcher" "group" - jmethod jinvoke ; + jinvoke ; -: groupCount (matcher -- count) +: group-count ( matcher -- count ) [ ] "java.util.regex.Matcher" "groupCount" - jmethod jinvoke ; + jinvoke ; -: groups* (matcher -- list) +: groups* ( matcher -- list ) [ [ - dup groupCount [ + dup group-count [ succ over group swap ] times* drop ] cons expand - ] [matches] ; + ] [re-matches] ; -: groups (input regex -- list) +: groups ( input regex -- list ) groups* ; -: [matches] ( matcher code -- boolean ) - ! If the matcher's matches* function returns true, +: index-of* ( index string substring -- index ) + dup char? [ + -rot + ! Why is the first parameter an int and not a char? + [ "int" "int" ] + "java.lang.String" "indexOf" + jinvoke + ] [ + -rot + [ "java.lang.String" "int" ] + "java.lang.String" "indexOf" + jinvoke + ] ifte ; + +: index-of ( string substring -- index ) + 0 -rot index-of* ; + +: [re-matches] ( matcher code -- boolean ) + ! If the matcher's re-matches* function returns true, ! evaluate the code with the matcher at the top of the ! stack. Otherwise, pop the matcher off the stack and ! push f. - [ dup matches* ] dip [ drop f ] ifte ; + [ dup re-matches* ] dip [ drop f ] ifte ; -: (string pattern -- matcher) +: ( string pattern -- matcher ) [ "java.lang.CharSequence" ] "java.util.regex.Pattern" "matcher" - jmethod jinvoke ; + jinvoke ; -: matches* (matcher -- boolean) +: re-matches* ( matcher -- boolean ) [ ] "java.util.regex.Matcher" "matches" - jmethod jinvoke ; + jinvoke ; -: matches (input regex -- boolean) - matches* ; +: re-matches ( input regex -- boolean ) + re-matches* ; -: replace* ( replace matcher -- string ) +: re-replace* ( replace matcher -- string ) [ "java.lang.String" ] "java.util.regex.Matcher" - "replaceAll" jmethod jinvoke ; + "replaceAll" jinvoke ; -: replace ( input regex replace -- string ) +: re-replace ( input regex replace -- string ) ! Replaces all occurrences of the regex in the input string ! with the replace string. - -rot replace* ; + -rot re-replace* ; + +: re-split ( string split -- list ) + [ "java.lang.CharSequence" ] + "java.util.regex.Pattern" "split" jinvoke array>list ; : (pattern -- regex) ! Compile the regex, if its not already compiled. dup "java.util.regex.Pattern" is not [ - [ "java.lang.String" ] "java.util.regex.Pattern" "compile" - jmethod jinvokeStatic + [ "java.lang.String" ] + "java.util.regex.Pattern" "compile" + jinvoke-static ] when ; -: strget (index str -- char) - [ "int" ] "java.lang.String" "charAt" jmethod jinvoke ; +: split ( string split -- list ) + 2dup index-of dup -1 = [ + 2drop unit + ] [ + swap [ str// ] dip split cons + ] ifte ; -: strlen (str -- length) - [ ] "java.lang.String" "length" jmethod jinvoke ; +: str/ ( str index -- str str ) + ! Returns 2 strings, that when concatenated yield the + ! original string. + 2dup strtail [ str-head ] dip ; -: streach (str [ code ] --) - ! Execute the code, with each character of the string pushed onto the - ! stack. - over strlen [ - -rot 2dup [ [ strget ] dip call ] 2dip +: str// ( str index -- str str ) + ! Returns 2 strings, that when concatenated yield the + ! original string, without the character at the given + ! index. + 2dup succ strtail [ str-head ] dip ; + +: str-each ( str [ code ] -- ) + ! Execute the code, with each character of the string pushed + ! onto the stack. + over str-length [ + -rot 2dup [ [ str-get ] dip call ] 2dip ] times* 2drop ; -: strmap (str initial [ code ] -- [ mapping ]) - ! If the 'initial' parameter is f, turn it into "". - ! Maybe cat should handle this instead? - [ dup [ drop "" ] unless ] dip - swapd [ ] cons cons cons - restack - streach - unstack cat ; +: str-expand ( [ code ] -- str ) + expand cat ; + +: str-get (index str -- char) + [ "int" ] "java.lang.String" "charAt" jinvoke ; + +: str-head ( str index -- str ) + ! Returns a new string, from the beginning of the string + ! until the given index. + 0 transp substring ; + +: str-headcut ( str begin -- str str ) + str-length str/ ; + +: str-head? ( str begin -- str ) + ! If the string starts with begin, return the rest of the + ! string after begin. Otherwise, return f. + 2dup str-length> [ + tuck str-headcut + [ = ] dip f ? + ] [ + 2drop f + ] ifte ; + +: str-length ( str -- length ) + [ ] "java.lang.String" "length" jinvoke ; + +: str-length> ( str str -- boolean ) + ! Compare string lengths. + [ str-length ] apply2 > ; + +: str-map ( str [ code ] -- [ mapping ] ) + 2list restack str-each unstack cat ; + +: strtail ( str index -- str ) + ! Returns a new string, from the given index until the end + ! of the string. + over str-length rot substring ; + +: substring ( start end str -- str ) + [ "int" "int" ] "java.lang.String" "substring" + jinvoke ; diff --git a/version.factor b/version.factor index aa23256b50..8f2710a217 100644 --- a/version.factor +++ b/version.factor @@ -1 +1 @@ -"0.29" @version +"0.36" @version