nomennescio 2019-10-18 15:04:32 +02:00
parent e29a64334c
commit fc8c5b6fec
68 changed files with 3987 additions and 1919 deletions

View File

@ -1,14 +1,24 @@
./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/CompiledList.java: * $Id: CompiledList.java,v 1.5 2004/03/07 22:51:00 slava Exp $
./factor/compiler/StackEffect.java: * $Id: StackEffect.java,v 1.12 2004/03/05 21:09:10 slava Exp $
./factor/compiler/Literal.java: * $Id: Literal.java,v 1.1 2004/02/28 19:51:53 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/compiler/CompiledDefinition.java:* $Id: CompiledDefinition.java,v 1.8 2004/03/07 22:51:00 slava Exp $
./factor/compiler/Result.java: * $Id: Result.java,v 1.1 2004/02/28 19:51:53 slava Exp $
./factor/compiler/ConstantPoolString.java: * $Id: ConstantPoolString.java,v 1.1 2004/02/28 19:51:53 slava Exp $
./factor/compiler/Null.java: * $Id: Null.java,v 1.2 2004/03/01 02:37:01 slava Exp $
./factor/compiler/RecursiveState.java: * $Id: RecursiveState.java,v 1.5 2004/03/28 21:25:13 slava Exp $
./factor/compiler/FactorCompiler.java: * $Id: FactorCompiler.java,v 1.11 2004/03/24 02:50:28 slava Exp $
./factor/compiler/RecursiveForm.java: * $Id: RecursiveForm.java,v 1.5 2004/03/04 23:33:42 slava Exp $
./factor/compiler/CompiledChoice.java: * $Id: CompiledChoice.java,v 1.7 2004/03/28 21:25:13 slava Exp $
./factor/compiler/FlowObject.java: * $Id: FlowObject.java,v 1.3 2004/03/28 21:25:13 slava Exp $
./factor/prettyprint.factor:! $Id: prettyprint.factor,v 1.3 2004/03/26 05:06:36 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/FactorJava.java: * $Id: FactorJava.java,v 1.18 2004/03/28 21:25:13 slava Exp $
./factor/combinators.factor:! $Id: combinators.factor,v 1.12 2004/03/24 02:50:28 slava Exp $
./factor/inspector.factor:! $Id: inspector.factor,v 1.3 2004/03/28 21:25:13 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/continuations.factor:! $Id: continuations.factor,v 1.3 2004/03/11 05:49:37 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 $
@ -16,53 +26,55 @@
./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/lists.factor:! $Id: lists.factor,v 1.17 2004/03/24 02:50:28 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/debugger.factor:! $Id: debugger.factor,v 1.6 2004/03/28 21:25:13 slava Exp $
./factor/FactorNamespace.java: * $Id: FactorNamespace.java,v 1.7 2004/02/24 18:55:09 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/examples.factor:! $Id: examples.factor,v 1.2 2004/02/26 05:35:20 slava Exp $
./factor/Cons.java: * $Id: Cons.java,v 1.8 2004/03/28 21:25:13 slava Exp $
./factor/FactorCompoundDefinition.java:* $Id: FactorCompoundDefinition.java,v 1.21 2004/03/26 05:06:36 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/FactorParser.java: * $Id: FactorParser.java,v 1.6 2004/03/28 21:25:13 slava Exp $
./factor/FactorMath.java: * $Id: FactorMath.java,v 1.4 2004/03/13 05:39:00 slava Exp $
./factor/parser.factor:! $Id: parser.factor,v 1.6 2004/03/28 21:25:13 slava Exp $
./factor/FactorMissingDefinition.java: * $Id: FactorMissingDefinition.java,v 1.8 2004/03/05 21:09:10 slava Exp $
./factor/stream.factor:! $Id: stream.factor,v 1.6 2004/03/28 21:25:13 slava Exp $
./factor/strings.factor:! $Id: strings.factor,v 1.18 2004/03/28 18:59:28 slava Exp $
./factor/FactorInterpreter.java: * $Id: FactorInterpreter.java,v 1.14 2004/03/28 21:25:13 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/FactorWord.java: * $Id: FactorWord.java,v 1.14 2004/03/26 05:06:36 slava Exp $
./factor/math.factor:! $Id: math.factor,v 1.11 2004/03/20 03:33:52 slava Exp $
./factor/FactorWordDefinition.java: * $Id: FactorWordDefinition.java,v 1.24 2004/03/28 21:25:13 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/JInvokeStatic.java: * $Id: JInvokeStatic.java,v 1.4 2004/02/28 19:51:53 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/JVarGetStatic.java: * $Id: JVarGetStatic.java,v 1.4 2004/02/28 19:51:53 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/JInvoke.java: * $Id: JInvoke.java,v 1.4 2004/02/28 19:51:53 slava Exp $
./factor/primitives/Get.java: * $Id: Get.java,v 1.4 2004/02/28 19:51:53 slava Exp $
./factor/primitives/Define.java: * $Id: Define.java,v 1.5 2004/03/26 05:06:36 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/Bind.java: * $Id: Bind.java,v 1.5 2004/02/28 19:51:53 slava Exp $
./factor/primitives/Choice.java: * $Id: Choice.java,v 1.6 2004/02/28 19:51:53 slava Exp $
./factor/primitives/Execute.java: * $Id: Execute.java,v 1.1 2004/02/24 03:23:00 slava Exp $
./factor/primitives/JNew.java: * $Id: JNew.java,v 1.4 2004/02/28 19:51:53 slava Exp $
./factor/primitives/Call.java: * $Id: Call.java,v 1.4 2004/02/28 19:51:53 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/JVarSet.java: * $Id: JVarSet.java,v 1.4 2004/02/28 19:51:53 slava Exp $
./factor/primitives/Set.java: * $Id: Set.java,v 1.4 2004/02/28 19:51:53 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/primitives/JVarSetStatic.java: * $Id: JVarSetStatic.java,v 1.4 2004/02/28 19:51:53 slava Exp $
./factor/primitives/JVarGet.java: * $Id: JVarGet.java,v 1.4 2004/02/28 19:51:53 slava Exp $
./factor/httpd.factor:! $Id: httpd.factor,v 1.4 2004/03/24 02:50:28 slava Exp $
./factor/interpreter.factor:! $Id: interpreter.factor,v 1.18 2004/03/28 21:25:13 slava Exp $
./factor/miscellaneous.factor:! $Id: miscellaneous.factor,v 1.9 2004/03/28 21:25:13 slava Exp $
./factor/FactorArrayStack.java: * $Id: FactorArrayStack.java,v 1.4 2004/03/28 21:25:13 slava Exp $
./factor/boot.factor:! $Id: boot.factor,v 1.16 2004/03/26 05:06:36 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/namespaces.factor:! $Id: namespaces.factor,v 1.7 2004/03/16 23:30:54 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 $
./factor/FactorShuffleDefinition.java: * $Id: FactorShuffleDefinition.java,v 1.15 2004/03/05 21:09:10 slava Exp $
./factor/dictionary.factor:! $Id: dictionary.factor,v 1.16 2004/03/28 18:59:28 slava Exp $

View File

@ -119,6 +119,35 @@ public class Cons implements PublicCloneable, FactorExternalizable
return size;
} //}}}
//{{{ nappend() method
public static Cons nappend(Cons l1, Cons l2)
{
if(l1 == null)
return l2;
if(l2 == null)
return l1;
Cons last = l1;
while(last.cdr != null)
last = last.next();
last.cdr = l2;
return l1;
} //}}}
//{{{ assoc() method
public static Object assoc(Cons assoc, Object key)
{
if(assoc == null)
return null;
else
{
Cons first = (Cons)assoc.car;
if(FactorLib.equal(first.car,key))
return first.cdr;
else
return assoc(assoc.next(),key);
}
} //}}}
//{{{ isProperList() method
public boolean isProperList()
{
@ -140,7 +169,7 @@ public class Cons implements PublicCloneable, FactorExternalizable
if(iter.car == this)
buf.append("<circular reference>");
else
buf.append(FactorJava.factorTypeToString(iter.car));
buf.append(FactorParser.unparse(iter.car));
if(iter.cdr instanceof Cons)
{
buf.append(' ');
@ -152,7 +181,7 @@ public class Cons implements PublicCloneable, FactorExternalizable
else
{
buf.append(" , ");
buf.append(FactorJava.factorTypeToString(iter.cdr));
buf.append(FactorParser.unparse(iter.cdr));
iter = null;
}
}

View File

@ -140,21 +140,4 @@ public abstract class FactorArrayStack implements FactorExternalizable
}
return first;
} //}}}
//{{{ toString() method
public String toString()
{
StringBuffer buf = new StringBuffer();
for(int i = 0; i < top; i++)
{
if(i != 0)
buf.append('\n');
buf.append(i).append(": ");
if(stack[i] == this)
buf.append("THIS STACK");
else
buf.append(FactorJava.factorTypeToString(stack[i]));
}
return buf.toString();
} //}}}
}

View File

@ -34,7 +34,6 @@ import java.lang.reflect.*;
import java.io.FileOutputStream;
import java.util.*;
import org.objectweb.asm.*;
import org.objectweb.asm.util.*;
/**
* : name ... ;
@ -60,22 +59,21 @@ public class FactorCompoundDefinition extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws Exception
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler compiler) throws Exception
{
if(recursiveCheck.contains(this))
return null;
try
RecursiveForm rec = recursiveCheck.get(word);
if(rec.active)
{
recursiveCheck.add(this);
StackEffect se = rec.baseCase;
if(se == null)
throw new FactorCompilerException("Indeterminate recursive call");
return StackEffect.getStackEffect(definition,
recursiveCheck,state);
compiler.apply(StackEffect.decompose(rec.effect,se));
}
finally
else
{
recursiveCheck.remove(this);
compiler.getStackEffect(definition,recursiveCheck);
}
} //}}}
@ -100,45 +98,40 @@ public class FactorCompoundDefinition extends FactorWordDefinition
* Compile the given word, returning a new word definition.
*/
FactorWordDefinition compile(FactorInterpreter interp,
Set recursiveCheck) throws Exception
RecursiveState 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");
StackEffect effect = getStackEffect();
/* StringBuffer buf = new StringBuffer();
for(int i = 0; i < recursiveCheck.size(); i++)
{
buf.append(' ');
}
buf.append("Compiling ").append(word);
System.err.println(buf); */
if(effect.inR != 0 || effect.outR != 0)
throw new FactorCompilerException("Compiled code cannot manipulate call stack frames");
boolean multipleReturns = (effect.outD > 1);
String className = getSanitizedName(word.name);
ClassWriter cw = new ClassWriter(false);
cw.visit(ACC_PUBLIC, className,
"factor/compiler/CompiledDefinition", null, null);
"factor/compiler/CompiledDefinition",
null, null);
compileConstructor(cw,className);
CompileResult result = compileEval(interp,cw,
className,effect,recursiveCheck);
className,effect,recursiveCheck,
multipleReturns);
compileToString(cw,effect);
// Generate fields for storing literals and
// word references
result.compiler.generateFields(cw);
// Generate fields for storing literals and word references
result.allocator.generateFields(cw);
// gets the bytecode of the class, and loads it dynamically
// gets the bytecode of the class, and loads it
// dynamically
byte[] code = cw.toByteArray();
if(interp.compileDump)
if(interp.dump)
{
FileOutputStream fos = new FileOutputStream(className + ".class");
FileOutputStream fos = new FileOutputStream(
className + ".class");
fos.write(code);
fos.close();
}
@ -147,17 +140,21 @@ public class FactorCompoundDefinition extends FactorWordDefinition
className.replace('/','.'),
code, 0, code.length);
result.allocator.setFields(compiledWordClass);
result.compiler.setFields(compiledWordClass);
Constructor constructor = compiledWordClass.getConstructor(
new Class[] { FactorWord.class, StackEffect.class });
Constructor constructor = compiledWordClass
.getConstructor(
new Class[] {
FactorWord.class, StackEffect.class, Cons.class
});
FactorWordDefinition compiledWord = (FactorWordDefinition)
constructor.newInstance(new Object[] { word, effect });
FactorWordDefinition compiledWord
= (FactorWordDefinition)
constructor.newInstance(
new Object[] { word, effect, definition });
// store disassembly for the 'asm' word.
compiledWord.getNamespace(interp).setVariable("asm",
result.asm);
word.asm = result.asm;
return compiledWord;
} //}}}
@ -168,7 +165,9 @@ public class FactorCompoundDefinition extends FactorWordDefinition
// creates a MethodWriter for the constructor
CodeVisitor mw = cw.visitMethod(ACC_PUBLIC,
"<init>",
"(Lfactor/FactorWord;Lfactor/compiler/StackEffect;)V",
"(Lfactor/FactorWord;"
+ "Lfactor/compiler/StackEffect;"
+ "Lfactor/Cons;)V",
null, null);
// pushes the 'this' variable
mw.visitVarInsn(ALOAD, 0);
@ -176,34 +175,27 @@ public class FactorCompoundDefinition extends FactorWordDefinition
mw.visitVarInsn(ALOAD, 1);
// pushes the stack effect parameter
mw.visitVarInsn(ALOAD, 2);
// pushes the definition parameter
mw.visitVarInsn(ALOAD, 3);
// invokes the super class constructor
mw.visitMethodInsn(INVOKESPECIAL,
"factor/compiler/CompiledDefinition", "<init>",
"(Lfactor/FactorWord;Lfactor/compiler/StackEffect;)V");
"(Lfactor/FactorWord;"
+ "Lfactor/compiler/StackEffect;"
+ "Lfactor/Cons;)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);
mw.visitMaxs(4, 4);
} //}}}
//{{{ compileEval() method
static class CompileResult
{
LocalAllocator allocator;
FactorCompiler compiler;
String asm;
CompileResult(LocalAllocator allocator, String asm)
CompileResult(FactorCompiler compiler, String asm)
{
this.allocator = allocator;
this.compiler = compiler;
this.asm = asm;
}
}
@ -215,73 +207,34 @@ public class FactorCompoundDefinition extends FactorWordDefinition
*/
protected CompileResult compileEval(FactorInterpreter interp,
ClassWriter cw, String className, StackEffect effect,
Set recursiveCheck) throws Exception
RecursiveState recursiveCheck, boolean multipleReturns)
throws Exception
{
// creates a MethodWriter for the 'eval' method
CodeVisitor _mw = cw.visitMethod(ACC_PUBLIC,
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);
mw.visitMethodInsn(INVOKESTATIC,className,"core",
effect.getCorePrototype());
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,
FactorCompiler compiler = new FactorCompiler(interp,word,
className,1,effect.inD);
String asm = compiler.compile(definition,cw,className,
"core",effect,recursiveCheck);
int maxJVMStack = allocator.compile(definition,mw,
recursiveCheck);
if(effect.outD == 0)
mw.visitInsn(RETURN);
else
{
allocator.pop(mw);
mw.visitInsn(ARETURN);
maxJVMStack = Math.max(maxJVMStack,1);
}
mw.visitMaxs(maxJVMStack,allocator.maxLocals());
String coreAsm = getDisassembly(mw);
return new CompileResult(allocator,
"eval(Lfactor/FactorInterpreter;)V:\n" + evalAsm
+ "core" + signature + "\n" + coreAsm);
} //}}}
//{{{ 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();
return new CompileResult(compiler,asm);
} //}}}
//{{{ compileDataStackToJVMStack() method
@ -358,16 +311,37 @@ public class FactorCompoundDefinition extends FactorWordDefinition
/**
* Compile a call to this word. Returns maximum JVM stack use.
*/
public int compileImmediate(CodeVisitor mw, LocalAllocator allocator,
Set recursiveCheck) throws Exception
public int compileImmediate(CodeVisitor mw, FactorCompiler compiler,
RecursiveState recursiveCheck) throws Exception
{
return allocator.compile(definition,mw,recursiveCheck);
/* System.err.println("immediate call to " + word);
FactorDataStack savedDatastack = (FactorDataStack)
compiler.datastack.clone();
FactorCallStack savedCallstack = (FactorCallStack)
compiler.callstack.clone();
StackEffect savedEffect = compiler.getStackEffect();
compiler.effect = new StackEffect();
RecursiveState _recursiveCheck = new RecursiveState();
_recursiveCheck.add(word,null);
getStackEffect(_recursiveCheck,compiler);
_recursiveCheck.remove(word);
StackEffect effect = compiler.getStackEffect();
System.err.println("immediate effect is " + effect);
compiler.datastack = savedDatastack;
compiler.callstack = savedCallstack;
compiler.effect = savedEffect; */
return compiler.compile(definition,mw,recursiveCheck);
} //}}}
//{{{ toString() method
public String toString()
//{{{ toList() method
public Cons toList()
{
return definition.elementsToString();
return new Cons(word,new Cons(new FactorWord("\n"),
definition));
} //}}}
private static SimpleClassLoader loader = new SimpleClassLoader();

View File

@ -1,165 +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 factor.primitives.*;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
public class FactorDictionary
{
public FactorWord last;
FactorWord datastackGet;
FactorWord datastackSet;
FactorWord clear;
FactorWord callstackGet;
FactorWord callstackSet;
FactorWord restack;
FactorWord unstack;
FactorWord unwind;
FactorWord jnew;
FactorWord jvarGet;
FactorWord jvarSet;
FactorWord jvarGetStatic;
FactorWord jvarSetStatic;
FactorWord jinvoke;
FactorWord jinvokeStatic;
FactorWord get;
FactorWord set;
FactorWord define;
FactorWord call;
FactorWord bind;
FactorWord choice;
private Map intern;
//{{{ init() method
public void init()
{
intern = new TreeMap();
// data stack primitives
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
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
jinvoke = intern("jinvoke");
jinvoke.def = new JInvoke(jinvoke);
jinvokeStatic = intern("jinvoke-static");
jinvokeStatic.def = new JInvokeStatic(
jinvokeStatic);
jnew = intern("jnew");
jnew.def = new JNew(jnew);
jvarGet = intern("jvar$");
jvarGet.def = new JVarGet(jvarGet);
jvarGetStatic = intern("jvar-static$");
jvarGetStatic.def = new JVarGetStatic(
jvarGetStatic);
jvarSet = intern("jvar@");
jvarSet.def = new JVarSet(jvarSet);
jvarSetStatic = intern("jvar-static@");
jvarSetStatic.def = new JVarSetStatic(
jvarSetStatic);
// namespaces
get = intern("$");
get.def = new Get(get);
set = intern("@");
set.def = new Set(set);
// definition
define = intern("define");
define.def = new Define(define);
// combinators
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
public FactorWord intern(String name)
{
FactorWord w = (FactorWord)intern.get(name);
if(w == null)
{
w = new FactorWord(name);
intern.put(name,w);
}
return w;
} //}}}
//{{{ toWordList() method
public Cons toWordList()
{
Cons first = null;
Cons last = null;
Iterator iter = intern.values().iterator();
while(iter.hasNext())
{
FactorWord word = (FactorWord)iter.next();
if(!(word.def instanceof FactorMissingDefinition))
{
Cons cons = new Cons(word,null);
if(first == null)
first = cons;
else
last.cdr = cons;
last = cons;
}
}
return first;
} //}}}
}

View File

@ -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,6 +29,7 @@
package factor;
import factor.primitives.*;
import java.io.*;
public class FactorInterpreter
@ -41,53 +42,20 @@ public class FactorInterpreter
public boolean trace = false;
public boolean errorFlag = false;
public boolean compile = true;
public boolean compileDump = false;
public boolean dump = false;
public FactorCallFrame callframe;
public FactorCallStack callstack = new FactorCallStack();
public FactorDataStack datastack = new FactorDataStack();
public final FactorDictionary dict = new FactorDictionary();
public FactorNamespace dict;
public FactorWord last;
public FactorNamespace global;
//{{{ main() method
/**
* Need to refactor this into Factor.
*/
public static void main(String[] args) throws Exception
{
FactorInterpreter interp = new FactorInterpreter();
interp.init(args,null);
/* if(virgin)
{
System.out.println("Mini-interpreter");
BufferedReader in = new BufferedReader(
new InputStreamReader(
System.in));
String line;
for(;;)
{
System.out.print("] ");
System.out.flush();
line = in.readLine();
if(line == null)
break;
FactorParser parser = new FactorParser(
"<mini>",new StringReader(line),
interp.dict);
Cons parsed = parser.parse();
interp.call(parsed);
interp.run();
System.out.println(interp.datastack);
}
}
else
{
interp.run();
} */
System.exit(0);
} //}}}
@ -98,12 +66,81 @@ public class FactorInterpreter
callstack.top = 0;
datastack.top = 0;
dict.init();
initDictionary();
initNamespace(root);
topLevel();
runBootstrap();
} //}}}
//{{{ initDictionary() method
private void initDictionary() throws Exception
{
dict = new FactorNamespace(null,null);
// data stack primitives
FactorWord datastackGet = intern("datastack$");
datastackGet.def = new DatastackGet(
datastackGet);
FactorWord datastackSet = intern("datastack@");
datastackSet.def = new DatastackSet(
datastackSet);
FactorWord clear = intern("clear");
clear.def = new Clear(clear);
// call stack primitives
FactorWord callstackGet = intern("callstack$");
callstackGet.def = new CallstackGet(
callstackGet);
FactorWord callstackSet = intern("callstack@");
callstackSet.def = new CallstackSet(
callstackSet);
FactorWord restack = intern("restack");
restack.def = new Restack(restack);
FactorWord unstack = intern("unstack");
unstack.def = new Unstack(unstack);
FactorWord unwind = intern("unwind");
unwind.def = new Unwind(unwind);
// reflection primitives
FactorWord jinvoke = intern("jinvoke");
jinvoke.def = new JInvoke(jinvoke);
FactorWord jinvokeStatic = intern("jinvoke-static");
jinvokeStatic.def = new JInvokeStatic(
jinvokeStatic);
FactorWord jnew = intern("jnew");
jnew.def = new JNew(jnew);
FactorWord jvarGet = intern("jvar$");
jvarGet.def = new JVarGet(jvarGet);
FactorWord jvarGetStatic = intern("jvar-static$");
jvarGetStatic.def = new JVarGetStatic(
jvarGetStatic);
FactorWord jvarSet = intern("jvar@");
jvarSet.def = new JVarSet(jvarSet);
FactorWord jvarSetStatic = intern("jvar-static@");
jvarSetStatic.def = new JVarSetStatic(
jvarSetStatic);
// namespaces
FactorWord get = intern("$");
get.def = new Get(get);
FactorWord set = intern("@");
set.def = new Set(set);
// definition
FactorWord define = intern("define");
define.def = new Define(define);
// combinators
FactorWord execute = intern("execute");
execute.def = new Execute(execute);
FactorWord call = intern("call");
call.def = new Call(call);
FactorWord bind = intern("bind");
bind.def = new Bind(bind);
FactorWord choice = intern("?");
choice.def = new Choice(choice);
} //}}}
//{{{ initNamespace() method
private void initNamespace(Object root) throws Exception
{
@ -111,9 +148,14 @@ public class FactorInterpreter
global.setVariable("interpreter",this);
String[] boundFields = { "compile", "compileDump",
global.setVariable("error-flag",
new FactorNamespace.VarBinding(
getClass().getField("errorFlag"),
this));
String[] boundFields = { "compile", "dump",
"interactive", "trace",
"dict", "errorFlag", "args" };
"dict", "args", "global", "last" };
for(int i = 0; i < boundFields.length; i++)
{
global.setVariable(boundFields[i],
@ -132,8 +174,8 @@ public class FactorInterpreter
new InputStreamReader(
getClass().getResourceAsStream(
initFile)),
dict);
call(dict.intern("[init]"),parser.parse());
this);
call(intern("[init]"),parser.parse());
run();
} //}}}
@ -175,7 +217,7 @@ public class FactorInterpreter
eval(ip.car);
}
catch(Exception e)
catch(Throwable e)
{
if(handleError(e))
return;
@ -186,7 +228,7 @@ public class FactorInterpreter
} //}}}
//{{{ handleError() method
private boolean handleError(Exception e)
private boolean handleError(Throwable e)
{
/* if(throwErrors)
{
@ -213,10 +255,10 @@ public class FactorInterpreter
datastack.push(FactorJava.unwrapException(e));
try
{
eval(dict.intern("break"));
eval(intern("break"));
return false;
}
catch(Exception e2)
catch(Throwable e2)
{
System.err.println("Exception when calling break:");
e.printStackTrace();
@ -236,7 +278,7 @@ public class FactorInterpreter
*/
public final void call(Cons code)
{
call(dict.intern("call"),code);
call(intern("call"),code);
} //}}}
//{{{ call() method
@ -302,14 +344,14 @@ public class FactorInterpreter
/**
* Evaluates a word.
*/
private void eval(Object obj) throws Exception
public void eval(Object obj) throws Exception
{
if(trace)
{
StringBuffer buf = new StringBuffer();
for(int i = 0; i < callstack.top; i++)
buf.append(' ');
buf.append(FactorJava.factorTypeToString(obj));
buf.append(FactorParser.unparse(obj));
System.err.println(buf);
}
@ -333,6 +375,25 @@ public class FactorInterpreter
datastack.push(obj);
} //}}}
//{{{ intern() method
public FactorWord intern(String name)
{
try
{
FactorWord w = (FactorWord)dict.getVariable(name);
if(w == null)
{
w = new FactorWord(name);
dict.setVariable(name,w);
}
return w;
}
catch(Exception e)
{
throw new RuntimeException(e);
}
} //}}}
//{{{ topLevel() method
/**
* Returns the parser to the top level context.
@ -342,7 +403,7 @@ public class FactorInterpreter
callstack.top = 0;
datastack.top = 0;
callframe = new FactorCallFrame(
dict.intern("[toplevel]"),
intern("[toplevel]"),
global,
null);
} //}}}

View File

@ -29,7 +29,7 @@
package factor;
import factor.compiler.LocalAllocator;
import factor.compiler.FactorCompiler;
import java.lang.reflect.*;
import java.util.Iterator;
import java.util.LinkedList;
@ -125,6 +125,18 @@ public class FactorJava implements Constants
return true;
} //}}}
//{{{ toByte() method
public static byte toByte(Object arg)
throws FactorDomainException
{
if(arg instanceof Number)
return ((Number)arg).byteValue();
else if(arg instanceof String)
return Byte.parseByte((String)arg);
else
throw new FactorDomainException(arg,byte.class);
} //}}}
//{{{ toChar() method
public static char toChar(Object arg)
throws FactorDomainException
@ -232,18 +244,75 @@ public class FactorJava implements Constants
}
} //}}}
//{{{ toBooleanArray() method
public static boolean[] toBooleanArray(Object arg)
throws FactorDomainException
{
if(arg == null)
return new boolean[0];
else if(arg instanceof Cons)
arg = toArray(arg,Object[].class);
try
{
boolean[] returnValue = new boolean[
Array.getLength(arg)];
for(int i = 0; i < returnValue.length; i++)
{
returnValue[i] = toBoolean(
Array.get(arg,i));
}
return returnValue;
}
catch(IllegalArgumentException e)
{
throw new FactorDomainException(arg,boolean[].class);
}
} //}}}
//{{{ toByteArray() method
public static byte[] toByteArray(Object arg)
throws FactorDomainException
{
if(arg == null)
return new byte[0];
else if(arg instanceof Cons)
arg = toArray(arg,Object[].class);
try
{
byte[] returnValue = new byte[
Array.getLength(arg)];
for(int i = 0; i < returnValue.length; i++)
{
returnValue[i] = toByte(
Array.get(arg,i));
}
return returnValue;
}
catch(IllegalArgumentException e)
{
throw new FactorDomainException(arg,byte[].class);
}
} //}}}
//{{{ toArray() method
public static Object[] toArray(Object arg)
throws FactorDomainException
{
return toArray(arg,Object.class);
return toArray(arg,Object[].class);
} //}}}
//{{{ toArray() method
public static Object[] toArray(Object arg, Class clas)
throws FactorDomainException
{
if(arg instanceof Cons)
if(arg == null)
{
return (Object[])Array.newInstance(
clas.getComponentType(),0);
}
else if(arg instanceof Cons)
{
Cons list = (Cons)arg;
Object[] array = (Object[])
@ -293,6 +362,10 @@ public class FactorJava implements Constants
? Boolean.TRUE
: Boolean.FALSE;
}
else if(clas == byte.class)
{
return new Byte(toByte(arg));
}
else if(clas == char.class)
{
return new Character(toChar(arg));
@ -319,7 +392,11 @@ public class FactorJava implements Constants
}
else if(clas.isArray())
{
Class comp = clas.getComponentType();
if(!comp.isPrimitive())
return toArray(arg,clas);
else if(comp == boolean.class)
return toBooleanArray(arg);
}
if(arg != null && !clas.isInstance(arg))
@ -343,25 +420,6 @@ public class FactorJava implements Constants
return arg;
} //}}}
//{{{ factorTypeToString() method
public static String factorTypeToString(Object obj)
{
// this is for string representations of lists and stacks
if(obj == null || obj.equals(Boolean.FALSE))
return "f";
else if(obj.equals(Boolean.TRUE))
return "t";
else if(obj instanceof String)
return '"' + obj.toString() + '"'; //XXX: escape
else if(obj instanceof Number
|| obj instanceof FactorExternalizable)
return obj.toString();
else if(obj instanceof Character)
return "#\\" + ((Character)obj).charValue();
else
return "( " + obj + " )";
} //}}}
//{{{ javaClassToVMClass() method
public static String javaClassToVMClass(Class clazz)
{
@ -583,6 +641,29 @@ public class FactorJava implements Constants
return e;
} //}}}
//{{{ getConversionMethodName() method
/**
* Returns method name for converting an object to the given type.
* Only for primitives.
*/
public static String getConversionMethodName(Class type)
{
if(type == short.class)
{
// not yet done.
return null;
}
else if(type.isPrimitive())
{
String name = type.getName();
return "to"
+ Character.toUpperCase(name.charAt(0))
+ name.substring(1);
}
else
return null;
} //}}}
//{{{ generateFromConversion() method
/**
* Unbox value at top of the stack.
@ -600,18 +681,15 @@ public class FactorJava implements Constants
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 == short.class
|| type == byte.class
|| type == char.class)
{
// not yet done.
methodName = null;
}
else if(type.isPrimitive())
methodName = getConversionMethodName(type);
else if(type == Class.class)
methodName = "toClass";
else if(type == FactorNamespace.class)
@ -620,7 +698,16 @@ public class FactorJava implements Constants
interpArg = true;
}
else if(type.isArray())
{
Class comp = type.getComponentType();
if(comp.isPrimitive())
{
methodName = getConversionMethodName(comp)
+ "Array";
}
else
methodName = "toArray";
}
if(methodName == null)
{

View File

@ -278,8 +278,7 @@ public class FactorMath
if(min == max)
return min;
int nextInt = random.nextInt();
return min + Math.abs(nextInt % (max - min + 1));
return min + random.nextInt(max - min + 1);
} //}}}
//{{{ randomFloat() method

View File

@ -50,6 +50,13 @@ public class FactorMissingDefinition extends FactorWordDefinition
throw new FactorUndefinedWordException(word);
} //}}}
//{{{ toList() method
public Cons toList()
{
return new Cons(new FactorWord("( missing: " + word + " )"),
null);
} //}}}
//{{{ toString() method
public String toString()
{

View File

@ -42,7 +42,7 @@ import java.util.List;
/**
* Manages the set of available words.
*/
public class FactorNamespace implements PublicCloneable
public class FactorNamespace implements PublicCloneable, FactorObject
{
private static FactorWord NULL = new FactorWord("( represent-f )");
private static FactorWord CHECK_PARENT = new FactorWord("( check-parent )");
@ -105,6 +105,12 @@ public class FactorNamespace implements PublicCloneable
}
} //}}}
//{{{ getNamespace() method
public FactorNamespace getNamespace(FactorInterpreter interp)
{
return this;
} //}}}
//{{{ getParent() method
public FactorNamespace getParent()
{
@ -200,20 +206,48 @@ public class FactorNamespace implements PublicCloneable
words.put(name,CHECK_PARENT);
} //}}}
//{{{ initAllFields() method
private void initAllFields()
{
if(obj != null)
{
try
{
Field[] fields = obj.getClass().getFields();
for(int i = 0; i < fields.length; i++)
{
Field f = fields[i];
if(Modifier.isStatic(f.getModifiers()))
continue;
words.put(f.getName(),
new VarBinding(f,obj));
}
}
catch(Exception e)
{
}
}
} //}}}
//{{{ toVarList() method
/**
* Returns a list of variable and word names defined in this namespace.
*/
public Cons toVarList()
{
initAllFields();
Cons first = null;
Cons last = null;
Iterator iter = words.entrySet().iterator();
while(iter.hasNext())
{
Map.Entry entry = (Map.Entry)iter.next();
if(entry.getValue() == CHECK_PARENT)
Object value = entry.getValue();
if(value == CHECK_PARENT)
continue;
else if(value == NULL)
value = null;
String name = (String)entry.getKey();
Cons cons = new Cons(name,null);
@ -235,18 +269,33 @@ public class FactorNamespace implements PublicCloneable
*/
public Cons toValueList()
{
initAllFields();
Cons first = null;
Cons last = null;
Iterator iter = words.entrySet().iterator();
while(iter.hasNext())
{
Map.Entry entry = (Map.Entry)iter.next();
if(entry.getValue() == CHECK_PARENT)
Object value = entry.getValue();
if(value == CHECK_PARENT)
continue;
else if(value == NULL)
value = null;
Cons cons = new Cons(
new Cons(entry.getKey(),
entry.getValue()),null);
if(value instanceof VarBinding)
{
try
{
value = ((VarBinding)value).get();
}
catch(Exception e)
{
}
}
Cons cons = new Cons(new Cons(entry.getKey(),value)
,null);
if(first == null)
first = last = cons;
else
@ -291,11 +340,10 @@ public class FactorNamespace implements PublicCloneable
{
if(obj == null)
{
return "( Namespace #" + Integer.toString(hashCode(),16)
+ " )";
return "Namespace #" + Integer.toString(hashCode(),16);
}
else
return "( Namespace: " + obj + " #" + hashCode() + " )";
return "Namespace: " + obj + " #" + hashCode();
} //}}}
//{{{ clone() method

View File

@ -52,32 +52,33 @@ public class FactorParser
private String filename;
private Reader in;
private FactorDictionary dict;
private FactorInterpreter interp;;
private StreamTokenizer st;
// sometimes one token is expanded into two words
private Object next;
//{{{ FactorParser constructor
public FactorParser(String filename, Reader in, FactorDictionary dict)
public FactorParser(String filename, Reader in,
FactorInterpreter interp)
{
this.filename = (filename == null ? "<eval>" : filename);
this.in = in;
this.dict = dict;
this.interp = interp;
DEF = dict.intern(":");
INE = dict.intern(";");
DEF = interp.intern(":");
INE = interp.intern(";");
SHU = dict.intern("~<<");
F = dict.intern("--");
FLE = dict.intern(">>~");
SHU = interp.intern("~<<");
F = interp.intern("--");
FLE = interp.intern(">>~");
DEFINE = dict.intern("define");
DEFINE = interp.intern("define");
BRA = dict.intern("[");
KET = dict.intern("]");
BRA = interp.intern("[");
KET = interp.intern("]");
COMMA = dict.intern(",");
COMMA = interp.intern(",");
st = new StreamTokenizer(in);
st.resetSyntax();
@ -293,13 +294,13 @@ public class FactorParser
// $foo is expanded into "foo" $
if(st.sval.charAt(0) == '$')
{
next = dict.intern("$");
next = interp.intern("$");
return st.sval.substring(1);
}
// @foo is expanded into "foo" @
else if(st.sval.charAt(0) == '@')
{
next = dict.intern("@");
next = interp.intern("@");
return st.sval.substring(1);
}
}
@ -308,7 +309,7 @@ public class FactorParser
if(st.sval.charAt(0) == '|')
return st.sval.substring(1);
return dict.intern(st.sval);
return interp.intern(st.sval);
case '"': case '\'':
return st.sval;
default:
@ -363,7 +364,7 @@ public class FactorParser
int counter;
if(name.startsWith("r:"))
{
next = dict.intern(name.substring(2));
next = interp.intern(name.substring(2));
counter = (FactorShuffleDefinition
.FROM_R_MASK
| consumeR++);
@ -378,7 +379,7 @@ public class FactorParser
}
else
{
error("Unexpected " + FactorJava.factorTypeToString(
error("Unexpected " + FactorParser.unparse(
next));
}
}
@ -407,7 +408,7 @@ public class FactorParser
FactorWord w = ((FactorWord)_shuffle.car);
String name = w.name;
if(name.startsWith("r:"))
w = dict.intern(name.substring(2));
w = interp.intern(name.substring(2));
Integer _index = (Integer)consumeMap.get(w);
if(_index == null)
@ -429,7 +430,7 @@ public class FactorParser
}
else
{
error("Unexpected " + FactorJava.factorTypeToString(
error("Unexpected " + FactorParser.unparse(
_shuffle.car));
}
_shuffle = _shuffle.next();
@ -544,4 +545,52 @@ public class FactorParser
{
throw new FactorParseException(filename,st.lineno(),msg);
} //}}}
//{{{ getUnreadableString() method
public static String getUnreadableString(String str)
{
return "#<" + str + ">";
} //}}}
//{{{ unparse() method
public static String unparse(Object obj)
{
// this is for string representations of lists and stacks
if(obj == null || obj.equals(Boolean.FALSE))
return "f";
else if(obj.equals(Boolean.TRUE))
return "t";
else if(obj instanceof String)
{
StringBuffer buf = new StringBuffer("\"");
String str = (String)obj;
for(int i = 0; i < str.length(); i++)
{
char ch = str.charAt(i);
switch(ch)
{
case '\n':
buf.append("\\n");
break;
case '\t':
buf.append("\\t");
break;
case '"':
buf.append("\\\"");
break;
default:
buf.append(ch);
}
}
buf.append('"');
return buf.toString();
}
else if(obj instanceof Number
|| obj instanceof FactorExternalizable)
return obj.toString();
else if(obj instanceof Character)
return "#\\" + ((Character)obj).charValue();
else
return getUnreadableString(obj.toString());
} //}}}
}

View File

@ -30,7 +30,7 @@
package factor;
import factor.compiler.*;
import java.util.Set;
import java.util.Map;
import org.objectweb.asm.*;
import org.objectweb.asm.util.*;
@ -109,14 +109,12 @@ public class FactorShuffleDefinition extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws FactorStackException
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler state) throws FactorStackException
{
state.ensure(state.datastack,consumeD);
state.ensure(state.callstack,consumeR);
eval(state.datastack,state.callstack);
return new StackEffect(consumeD,shuffleDlength,
consumeR,shuffleRlength);
} //}}}
//{{{ compile() method
@ -124,7 +122,7 @@ public class FactorShuffleDefinition extends FactorWordDefinition
* Compile the given word, returning a new word definition.
*/
FactorWordDefinition compile(FactorInterpreter interp,
Set recursiveCheck) throws Exception
RecursiveState recursiveCheck) throws Exception
{
return this;
} //}}}
@ -133,10 +131,10 @@ public class FactorShuffleDefinition extends FactorWordDefinition
/**
* Compile a call to this word. Returns maximum JVM stack use.
*/
public int compileCallTo(CodeVisitor mw, LocalAllocator allocator,
Set recursiveCheck) throws FactorStackException
public int compileCallTo(CodeVisitor mw, FactorCompiler compiler,
RecursiveState recursiveCheck) throws FactorStackException
{
eval(allocator.datastack,allocator.callstack);
eval(compiler.datastack,compiler.callstack);
return 0;
} //}}}
@ -213,6 +211,13 @@ public class FactorShuffleDefinition extends FactorWordDefinition
}
} //}}}
//{{{ toList() method
public Cons toList()
{
return new Cons(word,new Cons(
new FactorWord(toString()),null));
} //}}}
//{{{ toString() method
public String toString()
{

View File

@ -29,14 +29,18 @@
package factor;
import factor.compiler.FactorCompilerException;
import factor.compiler.*;
import java.util.*;
/**
* An internalized symbol.
*/
public class FactorWord implements FactorExternalizable
public class FactorWord implements FactorExternalizable, FactorObject
{
private static int gensymCount = 0;
private FactorNamespace namespace;
public final String name;
/**
@ -45,14 +49,9 @@ public class FactorWord implements FactorExternalizable
public FactorWordDefinition def;
/**
* Definition before compiling.
* Contains a string if this is compiled.
*/
public FactorWordDefinition uncompiled;
/**
* "define" pushes previous definitions onto this list, like a stack.
*/
public Cons history;
public String asm;
/**
* Is this word referenced from a compiled word?
@ -71,60 +70,69 @@ public class FactorWord implements FactorExternalizable
def = new FactorMissingDefinition(this);
} //}}}
//{{{ getNamespace() method
public FactorNamespace getNamespace(FactorInterpreter interp)
throws Exception
{
if(namespace == null)
namespace = new FactorNamespace(interp.global,this);
return namespace;
} //}}}
//{{{ gensym() method
/**
* Returns an un-internalized word with a unique name.
*/
public static FactorWord gensym()
{
return new FactorWord("( GENSYM:" + (gensymCount++) + " )");
} //}}}
//{{{ define() method
public void define(FactorWordDefinition def)
{
asm = null;
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;
this.def = def;
} //}}}
//{{{ compile() method
public void compile(FactorInterpreter interp)
{
compile(interp,new HashSet());
RecursiveState recursiveCheck = new RecursiveState();
recursiveCheck.add(this,null);
compile(interp,recursiveCheck);
recursiveCheck.remove(this);
} //}}}
//{{{ compile() method
public void compile(FactorInterpreter interp, Set recursiveCheck)
public void compile(FactorInterpreter interp, RecursiveState recursiveCheck)
{
if(def.compileFailed)
return;
//if(def.compileFailed)
// return;
System.err.println("Compiling " + this);
if(recursiveCheck.contains(this))
System.err.println("WARNING: cannot compile recursive calls: " + this);
//System.err.println("Compiling " + 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);
/*System.err.println("WARNING: cannot compile " + this
+ ": " + t.getMessage());
if(!(t instanceof FactorException))
t.printStackTrace();*/
}
} //}}}

View File

@ -30,16 +30,14 @@
package factor;
import factor.compiler.*;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
import org.objectweb.asm.*;
/**
* A word definition.
*/
public abstract class FactorWordDefinition implements FactorObject, Constants
public abstract class FactorWordDefinition implements Constants
{
private FactorNamespace namespace;
protected FactorWord word;
public boolean compileFailed;
@ -52,31 +50,39 @@ public abstract class FactorWordDefinition implements FactorObject, Constants
public abstract void eval(FactorInterpreter interp)
throws Exception;
//{{{ getNamespace() method
public FactorNamespace getNamespace(FactorInterpreter interp) throws Exception
//{{{ toList() method
public Cons toList()
{
if(namespace == null)
namespace = new FactorNamespace(interp.global,this);
return namespace;
return new Cons(new FactorWord(getClass().getName()),null);
} //}}}
//{{{ getStackEffect() method
public final StackEffect getStackEffect() throws Exception
{
return getStackEffect(new HashSet(),new LocalAllocator());
return getStackEffect(new RecursiveState());
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws Exception
public final StackEffect getStackEffect(RecursiveState recursiveCheck)
throws Exception
{
return null;
FactorCompiler compiler = new FactorCompiler();
recursiveCheck.add(word,new StackEffect());
getStackEffect(recursiveCheck,compiler);
recursiveCheck.remove(word);
return compiler.getStackEffect();
} //}}}
//{{{ getStackEffect() method
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler compiler) throws Exception
{
throw new FactorCompilerException("Cannot deduce stack effect of " + word);
} //}}}
//{{{ compile() method
FactorWordDefinition compile(FactorInterpreter interp,
Set recursiveCheck) throws Exception
RecursiveState recursiveCheck) throws Exception
{
return this;
} //}}}
@ -85,44 +91,99 @@ public abstract class FactorWordDefinition implements FactorObject, Constants
/**
* Compile a call to this word. Returns maximum JVM stack use.
*/
public int compileCallTo(CodeVisitor mw, LocalAllocator allocator,
Set recursiveCheck) throws Exception
{
StackEffect effect = getStackEffect();
if(effect == null)
{
// combinator; inline
return compileImmediate(mw,allocator,recursiveCheck);
}
else
public int compileCallTo(CodeVisitor mw, FactorCompiler compiler,
RecursiveState recursiveCheck) throws Exception
{
// normal word
mw.visitVarInsn(ALOAD,0);
allocator.generateArgs(mw,effect.inD,null);
String defclass;
StackEffect effect;
String defclass = getClass().getName().replace('.','/');
RecursiveForm rec = recursiveCheck.get(word);
if(rec != null && rec.active && compiler.word == word)
{
// recursive call!
defclass = compiler.className;
effect = compiler.word.def.getStackEffect();
}
else if(this instanceof FactorCompoundDefinition)
{
throw new FactorCompilerException("You are an idiot!");
}
else
{
defclass = getClass().getName()
.replace('.','/');
effect = getStackEffect();
}
compiler.generateArgs(mw,effect.inD,null);
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);
if(effect.outD == 0)
{
// do nothing
}
else if(effect.outD == 1)
{
compiler.push(mw);
}
else
{
// transfer from data stack to JVM locals
FactorDataStack datastack = compiler.datastack;
// allocate the appropriate number of locals
compiler.produce(compiler.datastack,effect.outD);
// store the datastack instance somewhere
mw.visitVarInsn(ALOAD,0);
mw.visitFieldInsn(GETFIELD,
"factor/FactorInterpreter",
"datastack",
"Lfactor/FactorDataStack;");
int datastackLocal = compiler.allocate();
mw.visitVarInsn(ASTORE,datastackLocal);
// put all elements from the real datastack
// into locals
for(int i = 0; i < effect.outD; i++)
{
mw.visitVarInsn(ALOAD,datastackLocal);
mw.visitMethodInsn(INVOKEVIRTUAL,
"factor/FactorDataStack",
"pop",
"()Ljava/lang/Object;");
Result destination = (Result)
datastack.stack[
datastack.top - i - 1];
mw.visitVarInsn(ASTORE,destination.getLocal());
}
}
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
public int compileImmediate(CodeVisitor mw, FactorCompiler compiler,
RecursiveState recursiveCheck) throws Exception
{
throw new FactorCompilerException("Cannot compile " + word + " in immediate mode");
} //}}}
//{{{ toString() method
public String toString()
{
return getClass().getName() + ": " + word;
} //}}}
}

View File

@ -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:
@ -54,6 +54,7 @@
~<< 2tuck A B C D -- C D A B C D >>~
~<< rdrop r:A -- >>~
~<< rover r:A r:B -- r:A r:B r:A >>~
~<< >r A -- r:A >>~
~<< 2>r A B -- r:A r:B >>~
~<< r> r:A -- A >>~
@ -73,8 +74,8 @@
<ireader> <breader> ;
: parse* (filename reader -- list)
$dict
[ |java.lang.String |java.io.Reader |factor.FactorDictionary ]
$interpreter
[ |java.lang.String |java.io.Reader |factor.FactorInterpreter ]
|factor.FactorParser jnew
[ ] |factor.FactorParser |parse jinvoke ;
@ -87,8 +88,11 @@
"/factor/combinators.factor" runResource
"/factor/continuations.factor" runResource
"/factor/debugger.factor" runResource
"/factor/dictionary.factor" runResource
"/factor/examples.factor" runResource
"/factor/httpd.factor" runResource
"/factor/inspector.factor" runResource
"/factor/interpreter.factor" runResource
"/factor/lists.factor" runResource
"/factor/math.factor" runResource
@ -96,9 +100,13 @@
"/factor/namespaces.factor" runResource
"/factor/network.factor" runResource
"/factor/parser.factor" runResource
"/factor/random.factor" runResource
"/factor/stream.factor" runResource
"/factor/prettyprint.factor" runResource
"/factor/random.factor" runResource
"/factor/strings.factor" runResource
"/factor/test/test.factor" runResource
t @user-init
: cli-param ( param -- )
dup "no-" str-head? dup [
@ -113,7 +121,19 @@
$args [ cli-arg ] each
! Compile all words now
$compile [ compileAll ] when
$compile [
compile-all
] when
$~ $/ ".factor-rc" cat3 @init-path
$user-init [
$init-path dup exists? [ run-file ] [ drop ] ifte
] when
! If we're run stand-alone, start the interpreter in the current tty.
$interactive [ initialInterpreterLoop ] when
$interactive [
[ @top-level-continuation ] callcc0
initial-interpreter-loop
] when

View File

@ -25,7 +25,7 @@
! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
: apply2 (x y [ code ] --)
: 2apply (x y [ code ] --)
! First applies the code to x, then to y.
2dup 2>r
nip call
@ -46,12 +46,12 @@
! callstack.
r:P r:T r:R1 r:R2 -- R1 r:P r:T r:R1 r:R2 >>~
~<< binrecLeft
~<< binrec-left
! Left recursion setup; put second value on callstack, put P, T, R1, R2
! on data stack (and leave them on the callstack too).
Value2 r:P r:T r:R1 r:R2 -- P T R1 R2 r:Value2 r:P r:T r:R1 r:R2 >>~
~<< binrecRight
~<< binrec-right
! Right recursion setup; put second value back on datastack, put
! P, T, R1, R2 on data stack. All quotations except for R2 are
! discarded from the callstack, since they're not needed anymore.
@ -67,8 +67,8 @@
binrecR1 call
! R1 has now produced two values on top of the data stack.
! Recurse twice.
binrecLeft binrec
binrecRight binrec
binrec-left binrec
binrec-right binrec
! Now call R2.
r> call
] ifte ;
@ -85,7 +85,7 @@
r>
call ;
: cond (list --)
: cond ( x list -- )
! The list is of this form:
! [ [ condition 1 ] [ code 1 ]
! [ condition 2 ] [ code 2 ]
@ -129,6 +129,21 @@
2drop
] ifte ;
~<< 2each{
A1 D1 A2 D2 C -- A1 A2 C r:D1 r:D2 r:C >>~
~<< }2each
r:D1 r:D2 r:C -- D1 D2 C >>~
: 2each ( [ list ] [ list ] [ code ] -- )
! Push each pair of elements from the 2 lists in turn, then
! execute the code.
over [
[ [ uncons ] 2apply ] dip 2each{ call }2each 2each
] [
drop drop drop
] ifte ;
: expand (list -- list)
! Evaluates the list on a new stack, and pushes the reversed stack onto the
! original stack. For example, "[ 0 1 2 dup * + ] expand" will evaluate to
@ -138,6 +153,11 @@
call
unstack ;
: forever ( code -- )
! The code is evaluated forever. Typically, a continuation
! is used to escape the infinite loop.
dup dip forever ;
: ifte (cond [if true] [if false] --)
? call ;
@ -155,8 +175,8 @@
! and evaluate R2. This combinator is similar to the linrec combinator in
! Joy, except in Joy, P does not affect the stack.
>r >r >r dup >r call [
r> drop r> call
r> drop r> drop
rdrop r> call
rdrop rdrop
] [
r> r> r> dup >r swap >r swap >r call
r> r> r> r> dup >r linrec
@ -168,18 +188,31 @@
! 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).
[ uncons push ] when* ;
: 2map ( [ list ] [ list ] [ code ] -- [ mapping ] )
! Applies the code to each pair of items, returns a list
! that contains the result of each application.
3list restack 2each unstack ;
: subset ( list code -- list )
! Applies code to each element of the given list, creating a new list
! containing the elements where the code returned a non-null value.
[ dupd call [ drop ] unless ] cons 2list
restack
each
unstack ;
: treerec ( list quot -- )
! Apply quot to each element of the list; if an element is a
! list, first quot is called with the list itself, then a
! recursive call to listrec is made.
over [
[ uncons ] dip tuck [
over list? [
2dup [ treerec ] 2dip
] when call
] 2dip treerec
] [
2drop
] ifte ;
: times (n [ code ] --)
! Evaluates code n times.
[
@ -202,6 +235,11 @@
: unless (cond [if false] --)
f swap ? call ;
: unless* ( cond false -- )
! If cond is f, pop it off the stack and evaluate false.
! Otherwise, leave it on the stack.
over [ drop ] [ nip call ] ifte ;
: when (cond [if true] --)
f ? call ;
@ -213,8 +251,7 @@
: while ( [ P ] [ R ] -- ... )
! Evaluates P. If it leaves t on the stack, evaluate R, and recurse.
>r dup >r call [
r> r> dup >r swap >r call
r> r> while
rover r> call r> r> while
] [
r> drop r> drop
rdrop rdrop
] ifte ;

View File

@ -0,0 +1,316 @@
/* :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 CompiledChoice extends FlowObject implements Constants
{
FlowObject cond, t, f;
//{{{ CompiledChoice constructor
CompiledChoice(FlowObject cond, FlowObject t, FlowObject f,
FactorCompiler compiler, RecursiveState recursiveCheck)
{
super(compiler,recursiveCheck);
this.cond = cond;
this.t = t;
this.f = f;
} //}}}
//{{{ generate() method
public 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);
} //}}}
//{{{ usingLocal() method
boolean usingLocal(int local)
{
return cond.usingLocal(local)
|| t.usingLocal(local)
|| f.usingLocal(local);
} //}}}
//{{{ getStackEffect() method
/**
* Stack effect of executing this -- only used for lists
* and conditionals!
*/
public void getStackEffect(RecursiveState recursiveCheck)
throws Exception
{
StackEffect onEntry = recursiveCheck.last().effect;
FactorDataStack datastackCopy = (FactorDataStack)
compiler.datastack.clone();
FactorCallStack callstackCopy = (FactorCallStack)
compiler.callstack.clone();
StackEffect effectCopy = (StackEffect)
compiler.getStackEffect();
StackEffect te = compiler.getStackEffectOrNull(
t,recursiveCheck,false);
//System.err.println("te=" + te);
/** Other branch. */
FactorDataStack obDatastack = compiler.datastack;
FactorCallStack obCallstack = compiler.callstack;
StackEffect obEffect = compiler.getStackEffect();
compiler.datastack = (FactorDataStack)
datastackCopy.clone();
compiler.callstack = (FactorCallStack)
callstackCopy.clone();
compiler.effect = (StackEffect)effectCopy.clone();
StackEffect fe = compiler.getStackEffectOrNull(
f,recursiveCheck,false);
//System.err.println("fe=" + fe);
//System.err.println("rec=" + rec);
if(fe != null && te == null)
{
RecursiveForm rec = t.getWord();
if(rec == null)
throw new FactorCompilerException("Unscoped quotation: " + t);
rec.baseCase = fe;
//System.err.println("base=" + fe);
compiler.datastack = (FactorDataStack)
datastackCopy.clone();
compiler.callstack = (FactorCallStack)
callstackCopy.clone();
compiler.effect = (StackEffect)
effectCopy.clone();
t.getStackEffect(recursiveCheck);
te = compiler.getStackEffect();
//te = StackEffect.decompose(onEntry,te);
//System.err.println("te=" + te);
}
else if(fe == null && te != null)
{
RecursiveForm rec = f.getWord();
if(rec == null)
throw new FactorCompilerException("Unscoped quotation: " + t);
//System.err.println("base=" + te);
rec.baseCase = te;
compiler.datastack = (FactorDataStack)
datastackCopy.clone();
compiler.callstack = (FactorCallStack)
callstackCopy.clone();
compiler.effect = (StackEffect)
effectCopy.clone();
f.getStackEffect(recursiveCheck);
fe = compiler.getStackEffect();
//fe = StackEffect.decompose(onEntry,te);
//System.err.println("fe=" + fe);
}
if(te == null || fe == null)
throw new FactorCompilerException("Indeterminate recursive choice");
// 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)
{
throw new FactorCompilerException("Stack effect of " + t + " " + te + " is inconsistent with " + f + " " + fe + ", head is " + effectCopy);
}
// find how many elements of the t branch match with the f
// branch and don't discard those.
int highestEqual = 0;
for(highestEqual = 0; highestEqual < fe.outD; highestEqual++)
{
Object o1 = obDatastack.stack[
obDatastack.top - highestEqual - 1];
Object o2 = compiler.datastack.stack[
obDatastack.top - highestEqual - 1];
if(!o1.equals(o2))
break;
}
// replace results from the f branch with
// dummy values so that subsequent code
// doesn't assume these values always
// result from this
compiler.datastack.top -= fe.outD;
compiler.produce(compiler.datastack,fe.outD - highestEqual);
compiler.datastack.top += highestEqual;
compiler.callstack.top -= fe.outR;
compiler.produce(compiler.callstack,fe.outR);
compiler.effect = 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)
);
} //}}}
//{{{ compileCallTo() method
/**
* Write code for evaluating this. Returns maximum JVM stack
* usage.
*/
public int compileCallTo(CodeVisitor mw, RecursiveState 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);
int maxJVMStack = 1;
/* if(t instanceof Null && f instanceof Null)
{
// nothing to do!
mw.visitInsn(POP);
}
else if(t instanceof Null)
{
mw.visitJumpInsn(IFNONNULL,endl);
maxJVMStack = Math.max(maxJVMStack,
f.compileCallTo(mw,recursiveCheck));
mw.visitLabel(endl);
}
else if(f instanceof Null)
{
mw.visitJumpInsn(IFNULL,endl);
maxJVMStack = Math.max(maxJVMStack,
t.compileCallTo(mw,recursiveCheck));
mw.visitLabel(endl);
}
else */
{
mw.visitJumpInsn(IFNULL,fl);
FactorDataStack datastackCopy
= (FactorDataStack)
compiler.datastack.clone();
FactorCallStack callstackCopy
= (FactorCallStack)
compiler.callstack.clone();
maxJVMStack = Math.max(maxJVMStack,
t.compileCallTo(mw,recursiveCheck));
maxJVMStack = Math.max(maxJVMStack,
normalizeStacks(mw));
compiler.datastack = datastackCopy;
compiler.callstack = callstackCopy;
mw.visitJumpInsn(GOTO,endl);
mw.visitLabel(fl);
maxJVMStack = Math.max(maxJVMStack,
f.compileCallTo(mw,recursiveCheck));
maxJVMStack = Math.max(maxJVMStack,
normalizeStacks(mw));
mw.visitLabel(endl);
}
return maxJVMStack;
} //}}}
//{{{ normalizeStacks() method
private int normalizeStacks(CodeVisitor mw)
{
int datastackTop = compiler.datastack.top;
compiler.datastack.top = 0;
int callstackTop = compiler.callstack.top;
compiler.callstack.top = 0;
normalizeStack(compiler.datastack,datastackTop,mw);
normalizeStack(compiler.callstack,callstackTop,mw);
return Math.max(datastackTop,callstackTop);
} //}}}
//{{{ normalizeStack() method
private void normalizeStack(FactorArrayStack stack, int top,
CodeVisitor mw)
{
for(int i = top - 1; i >= 0; i--)
{
FlowObject obj = (FlowObject)stack.stack[i];
obj.generate(mw);
}
for(int i = 0; i < top; i++)
{
int local = compiler.allocate();
stack.push(new Result(local,compiler,null));
mw.visitVarInsn(ASTORE,local);
}
} //}}}
//{{{ toString() method
public String toString()
{
return FactorParser.unparse(f)
+ " "
+ FactorParser.unparse(t)
+ " ? call";
} //}}}
}

View File

@ -31,28 +31,39 @@ package factor.compiler;
import factor.*;
import java.lang.reflect.*;
import java.util.Set;
import java.util.Map;
import org.objectweb.asm.*;
/**
* : name ... ;
* Compiled colon definition.
*/
public abstract class CompiledDefinition
extends FactorWordDefinition
{
private StackEffect effect;
private Cons definition;
//{{{ CompiledDefinition constructor
public CompiledDefinition(FactorWord word, StackEffect effect)
public CompiledDefinition(FactorWord word, StackEffect effect,
Cons definition)
{
super(word);
this.effect = effect;
this.definition = definition;
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state)
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler compiler)
{
return effect;
compiler.apply(effect);
} //}}}
//{{{ toList() method
public Cons toList()
{
return new Cons(word,new Cons(effect,
new Cons(new FactorWord("\n"),
definition)));
} //}}}
}

View File

@ -0,0 +1,99 @@
/* :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 CompiledList extends FlowObject implements Constants
{
private Cons quotation;
private RecursiveState recursiveCheck;
CompiledList(Cons quotation, FactorCompiler compiler,
RecursiveState recursiveCheck)
{
super(compiler,recursiveCheck);
this.quotation = quotation;
// clone it
this.recursiveCheck = new RecursiveState(
recursiveCheck);
}
public void generate(CodeVisitor mw)
{
mw.visitFieldInsn(GETSTATIC,compiler.className,
compiler.literal(quotation),
"Ljava/lang/Object;");
}
Object getLiteral()
{
return quotation;
}
/**
* Stack effect of executing this -- only used for lists
* and conditionals!
*/
public void getStackEffect(RecursiveState recursiveCheck)
throws Exception
{
// important: this.recursiveCheck due to
// lexically-scoped recursion issues
compiler.getStackEffect(quotation,this.recursiveCheck);
}
/**
* Write code for evaluating this. Returns maximum JVM stack
* usage.
*/
public int compileCallTo(CodeVisitor mw,
RecursiveState recursiveCheck)
throws Exception
{
// important: this.recursiveCheck due to
// lexically-scoped recursion issues
return compiler.compile(quotation,mw,this.recursiveCheck);
}
public boolean equals(Object o)
{
if(o instanceof CompiledList)
{
CompiledList c = (CompiledList)o;
return FactorLib.objectsEqual(c.quotation,quotation);
}
else
return false;
}
}

View File

@ -0,0 +1,57 @@
/* :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 ConstantPoolString extends FlowObject
{
private String str;
ConstantPoolString(String str, FactorCompiler compiler,
RecursiveState recursiveCheck)
{
super(compiler,recursiveCheck);
this.str = str;
}
public void generate(CodeVisitor mw)
{
mw.visitLdcInsn(str);
}
Object getLiteral()
{
return str;
}
}

View File

@ -0,0 +1,571 @@
/* :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.*;
import org.objectweb.asm.util.*;
public class FactorCompiler implements Constants
{
private FactorInterpreter interp;
public final FactorWord word;
public final String className;
private int base;
private int max;
public FactorDataStack datastack;
public FactorCallStack callstack;
private int literalCount;
private Map literals = new HashMap();
public StackEffect effect = new StackEffect();
//{{{ FactorCompiler constructor
/**
* For balancing.
*/
public FactorCompiler()
{
this(null,null,null,0,0);
} //}}}
//{{{ FactorCompiler constructor
/**
* For compiling.
*/
public FactorCompiler(FactorInterpreter interp,
FactorWord word, String className,
int base, int allot)
{
this.interp = interp;
this.word = word;
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,this,null));
}
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)
{
if(stack == datastack)
effect.inD += (count - top);
else if(stack == callstack)
effect.inR += (count - top);
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(),this,null);
}
stack.top = count;
}
} //}}}
//{{{ consume() method
public void consume(FactorArrayStack stack, int count)
{
ensure(stack,count);
stack.top -= count;
} //}}}
//{{{ produce() method
public void produce(FactorArrayStack stack, int count)
{
for(int i = 0; i < count; i++)
stack.push(new Result(allocate(),this,null));
} //}}}
//{{{ apply() method
public void apply(StackEffect se)
{
consume(datastack,se.inD);
produce(datastack,se.outD);
consume(callstack,se.inR);
produce(callstack,se.outR);
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect()
{
effect.outD = datastack.top;
effect.outR = callstack.top;
return (StackEffect)effect.clone();
} //}}}
//{{{ getStackEffect() method
public void getStackEffect(Cons definition,
RecursiveState recursiveCheck)
throws Exception
{
while(definition != null)
{
Object obj = definition.car;
if(obj instanceof FactorWord)
{
FactorWord word = (FactorWord)obj;
RecursiveForm rec = recursiveCheck.get(word);
if(rec == null)
recursiveCheck.add(word,getStackEffect());
else
rec.active = true;
word.def.getStackEffect(recursiveCheck,this);
if(rec == null)
recursiveCheck.remove(word);
else
rec.active = false;
}
else
pushLiteral(obj,recursiveCheck);
definition = definition.next();
}
} //}}}
//{{{ 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();
} //}}}
//{{{ compile() method
/**
* Compiles a method and returns the disassembly.
*/
public String compile(Cons definition, ClassWriter cw, String className,
String methodName, StackEffect effect,
RecursiveState recursiveCheck)
throws Exception
{
String signature = effect.getCorePrototype();
CodeVisitor _mw = cw.visitMethod(ACC_PUBLIC | ACC_STATIC,
methodName,signature,null,null);
TraceCodeVisitor mw = new TraceCodeVisitor(_mw);
int maxJVMStack = compile(definition,mw,
recursiveCheck);
// special case where return value is passed on
// JVM operand stack
if(effect.outD == 0)
{
mw.visitInsn(RETURN);
}
else if(effect.outD == 1)
{
pop(mw);
mw.visitInsn(ARETURN);
maxJVMStack = Math.max(maxJVMStack,1);
}
else
{
// store datastack in a local
mw.visitVarInsn(ALOAD,0);
mw.visitFieldInsn(GETFIELD,
"factor/FactorInterpreter",
"datastack",
"Lfactor/FactorDataStack;");
int datastackLocal = allocate();
mw.visitVarInsn(ASTORE,datastackLocal);
for(int i = 0; i < datastack.top; i++)
{
mw.visitVarInsn(ALOAD,datastackLocal);
((FlowObject)datastack.stack[i])
.generate(mw);
mw.visitMethodInsn(INVOKEVIRTUAL,
"factor/FactorDataStack",
"push",
"(Ljava/lang/Object;)V");
}
datastack.top = 0;
mw.visitInsn(RETURN);
maxJVMStack = Math.max(2,maxJVMStack);
}
mw.visitMaxs(maxJVMStack,max);
return getDisassembly(mw);
} //}}}
//{{{ compile() method
/**
* Compiles a quotation and returns the maximum JVM stack depth.
*/
public int compile(Cons definition, CodeVisitor mw,
RecursiveState recursiveCheck) throws Exception
{
int maxJVMStack = 0;
while(definition != null)
{
Object obj = definition.car;
if(obj instanceof FactorWord)
{
maxJVMStack = Math.max(maxJVMStack,
compileWord((FactorWord)obj,mw,
recursiveCheck));
}
else
pushLiteral(obj,recursiveCheck);
definition = definition.next();
}
return maxJVMStack;
} //}}}
//{{{ compileWord() method
private int compileWord(FactorWord w, CodeVisitor mw,
RecursiveState recursiveCheck) throws Exception
{
RecursiveForm rec = recursiveCheck.get(w);
try
{
boolean recursiveCall;
if(rec == null)
{
recursiveCall = false;
recursiveCheck.add(w,null);
}
else
{
recursiveCall = true;
rec.active = true;
}
FactorWordDefinition d = w.def;
if(!recursiveCall)
{
StackEffect effect = getStackEffectOrNull(d);
if(effect == null)
{
return d.compileImmediate(mw,this,
recursiveCheck);
}
else if(d instanceof FactorCompoundDefinition)
{
w.compile(interp,recursiveCheck);
if(d == w.def)
{
throw new FactorCompilerException(word + " depends on " + w + " which cannot be compiled");
}
d = w.def;
}
}
w.compileRef = true;
return d.compileCallTo(mw,this,recursiveCheck);
}
finally
{
if(rec == null)
recursiveCheck.remove(w);
else
rec.active = false;
}
} //}}}
//{{{ 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,this,null));
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,this,null));
if(mw != null)
mw.visitVarInsn(ASTORE,local);
} //}}}
//{{{ pushLiteral() method
public void pushLiteral(Object literal, RecursiveState recursiveCheck)
{
if(literal == null)
datastack.push(new Null(this,recursiveCheck));
else if(literal instanceof Cons)
{
datastack.push(new CompiledList((Cons)literal,this,
recursiveCheck));
}
else if(literal instanceof String)
{
datastack.push(new ConstantPoolString((String)literal,
this,recursiveCheck));
}
else
{
datastack.push(new Literal(literal,this,
recursiveCheck));
}
} //}}}
//{{{ pushChoice() method
public void pushChoice(RecursiveState recursiveCheck)
throws FactorStackException
{
FlowObject f = (FlowObject)datastack.pop();
FlowObject t = (FlowObject)datastack.pop();
FlowObject cond = (FlowObject)datastack.pop();
datastack.push(new CompiledChoice(
cond,t,f,this,recursiveCheck));
} //}}}
//{{{ 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.
*/
public int allocate()
{
// inefficient!
int i = base;
for(;;)
{
if(allocate(i,datastack) && allocate(i,callstack))
{
max = Math.max(max,i + 1);
return i;
}
else
i++;
}
} //}}}
//{{{ 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;
} //}}}
//{{{ literal() method
public 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);
}
} //}}}
//{{{ 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);
}
} //}}}
//{{{ getStackEffectOrNull() method
static StackEffect getStackEffectOrNull(FactorWordDefinition def)
{
try
{
return def.getStackEffect();
}
catch(Exception e)
{
//System.err.println("WARNING: " + e);
//System.err.println(def);
return null;
}
} //}}}
//{{{ getStackEffectOrNull() method
StackEffect getStackEffectOrNull(FlowObject obj,
RecursiveState recursiveCheck,
boolean decompose)
{
try
{
obj.getStackEffect(recursiveCheck);
StackEffect effect = getStackEffect();
if(decompose)
{
effect = StackEffect.decompose(
recursiveCheck.last().effect,
effect);
}
return effect;
}
catch(Exception e)
{
//System.err.println("WARNING: " + e);
//System.err.println(obj);
return null;
}
} //}}}
}

View File

@ -0,0 +1,102 @@
/* :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 abstract class FlowObject
{
protected FactorCompiler compiler;
protected RecursiveForm word;
FlowObject(FactorCompiler compiler,
RecursiveState recursiveCheck)
{
this.compiler = compiler;
if(recursiveCheck != null)
word = recursiveCheck.last();
}
public abstract void generate(CodeVisitor mw);
boolean usingLocal(int local)
{
return false;
}
Object getLiteral()
throws FactorCompilerException
{
throw new FactorCompilerException("Cannot compile unless literal on stack: " + this);
}
/**
* Stack effect of evaluating this -- only used for lists
* and conditionals!
*/
public void getStackEffect(RecursiveState recursiveCheck)
throws Exception
{
throw new FactorCompilerException("Not a quotation: " + this);
}
/**
* Write code for evaluating this. Returns maximum JVM stack
* usage.
*/
public int compileCallTo(CodeVisitor mw, RecursiveState recursiveCheck)
throws Exception
{
throw new FactorCompilerException("Cannot compile call to non-literal quotation");
}
/**
* Returns the word where this flow object originated from.
*/
public RecursiveForm getWord()
{
return word;
}
public String toString()
{
try
{
return FactorParser.unparse(getLiteral());
}
catch(Exception e)
{
throw new RuntimeException("Override toString() if your getLiteral() bombs!");
}
}
}

View File

@ -0,0 +1,69 @@
/* :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 Literal extends FlowObject implements Constants
{
private Object literal;
Literal(Object literal, FactorCompiler compiler,
RecursiveState recursiveCheck)
{
super(compiler,recursiveCheck);
this.literal = literal;
}
public void generate(CodeVisitor mw)
{
mw.visitFieldInsn(GETSTATIC,compiler.className,
compiler.literal(literal),
"Ljava/lang/Object;");
}
Object getLiteral()
{
return literal;
}
/**
* Write code for evaluating this. Returns maximum JVM stack
* usage.
*/
public int compileCallTo(CodeVisitor mw, RecursiveState recursiveCheck)
throws Exception
{
throw new FactorCompilerException("Not a quotation: " + literal);
}
}

View File

@ -1,677 +0,0 @@
/* :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);
}
} //}}}
}

76
factor/compiler/Null.java Normal file
View File

@ -0,0 +1,76 @@
/* :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 Null extends FlowObject implements Constants
{
Null(FactorCompiler compiler, RecursiveState recursiveCheck)
{
super(compiler,recursiveCheck);
}
public void generate(CodeVisitor mw)
{
mw.visitInsn(ACONST_NULL);
}
Object getLiteral()
{
return null;
}
/**
* Stack effect of executing this -- only used for lists
* and conditionals!
*/
public void getStackEffect(RecursiveState recursiveCheck)
{
}
/**
* Write code for evaluating this. Returns maximum JVM stack
* usage.
*/
public int compileCallTo(CodeVisitor mw, RecursiveState recursiveCheck)
throws Exception
{
return 0;
}
public boolean equals(Object o)
{
return (o instanceof Null);
}
}

View File

@ -0,0 +1,53 @@
/* :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.FactorWord;
public class RecursiveForm
{
public final FactorWord word;
public StackEffect effect;
public StackEffect baseCase;
public boolean active;
public RecursiveForm(FactorWord word, StackEffect effect)
{
this.word = word;
this.effect = effect;
}
public String toString()
{
return word.toString() + (
baseCase == null
? "" : "-" + baseCase);
}
}

View File

@ -0,0 +1,98 @@
/* :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 RecursiveState
{
private Cons words;
//{{{ RecursiveState constructor
public RecursiveState()
{
} //}}}
//{{{ RecursiveState constructor
public RecursiveState(RecursiveState clone)
{
words = clone.words;
} //}}}
//{{{ add() method
public void add(FactorWord word, StackEffect effect)
{
//System.err.println(this + ": adding " + word);
//System.err.println(words);
if(get(word) != null)
{
//System.err.println("throwing exception");
throw new RuntimeException("Calling add() twice on " + word);
}
words = new Cons(new RecursiveForm(word,effect),words);
} //}}}
//{{{ remove() method
public void remove(FactorWord word)
{
//System.err.println(this + ": removing " + word);
if(last().word != word)
throw new RuntimeException("Unbalanced add()/remove()");
words = words.next();
} //}}}
//{{{ get() method
public RecursiveForm get(FactorWord word)
{
Cons iter = words;
while(iter != null)
{
RecursiveForm form = (RecursiveForm)iter.car;
//System.err.println(form.word + "==?" + word);
if(form.word == word)
return form;
iter = iter.next();
}
return null;
} //}}}
//{{{ last() method
public RecursiveForm last()
{
return (RecursiveForm)words.car;
} //}}}
//{{{ toString() method
public String toString()
{
return FactorParser.unparse(words);
} //}}}
}

View File

@ -0,0 +1,67 @@
/* :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 Result extends FlowObject implements Constants
{
private int local;
public Result(int local, FactorCompiler compiler,
RecursiveState recursiveCheck)
{
super(compiler,recursiveCheck);
this.local = local;
}
public void generate(CodeVisitor mw)
{
mw.visitVarInsn(ALOAD,local);
}
public int getLocal()
{
return local;
}
boolean usingLocal(int local)
{
return (this.local == local);
}
public String toString()
{
return "( indeterminate )";
}
}

View File

@ -32,12 +32,16 @@ package factor.compiler;
import factor.*;
import java.util.*;
public class StackEffect
public class StackEffect implements PublicCloneable, FactorExternalizable
{
public final int inD;
public final int outD;
public final int inR;
public final int outR;
public int inD;
public int outD;
public int inR;
public int outR;
//{{{ StackEffect constructor
public StackEffect() {}
//}}}
//{{{ StackEffect constructor
public StackEffect(int inD, int outD, int inR, int outR)
@ -48,69 +52,57 @@ public class StackEffect
this.outR = outR;
} //}}}
//{{{ getStackEffect() method
public static StackEffect getStackEffect(Cons definition)
throws Exception
//{{{ compose() method
public static StackEffect compose(StackEffect first,
StackEffect second)
{
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)
if(first == null || second == null)
return null;
if(se.inD <= outD)
outD -= se.inD;
int inD = first.inD;
int inR = first.inR;
int outD = first.outD;
int outR = first.outR;
if(second.inD <= outD)
outD -= second.inD;
else
{
inD += (se.inD - outD);
inD += (second.inD - outD);
outD = 0;
}
if(se.inR <= outR)
outR -= se.inR;
if(second.inR <= outR)
outR -= second.inR;
else
{
inR += (se.inR - outR);
inR += (second.inR - outR);
outR = 0;
}
outD += se.outD;
outR += se.outR;
}
else
{
outD++;
state.pushLiteral(obj);
}
iter = iter.next();
}
outD += second.outD;
outR += second.outR;
return new StackEffect(inD,outD,inR,outR);
} //}}}
//{{{ decompose() method
/**
* Returns a stack effect E such that compose(first,E) == second.
*/
public static StackEffect decompose(StackEffect first,
StackEffect second)
{
if(second.inD < first.inD || second.inR < first.inR)
throw new IllegalArgumentException();
return new StackEffect(
first.outD + second.inD - first.inD,
second.outD,
first.outR + second.inR - first.inR,
second.outR);
} //}}}
//{{{ getCorePrototype() method
public String getCorePrototype()
{
@ -122,7 +114,7 @@ public class StackEffect
signatureBuf.append("Ljava/lang/Object;");
}
if(outD == 0)
if(outD != 1)
signatureBuf.append(")V");
else
signatureBuf.append(")Ljava/lang/Object;");
@ -145,24 +137,31 @@ public class StackEffect
//{{{ toString() method
public String toString()
{
StringBuffer buf = new StringBuffer();
StringBuffer buf = new StringBuffer("( ");
for(int i = 0; i < inD; i++)
{
buf.append("I ");
buf.append("X ");
}
for(int i = 0; i < inR; i++)
{
buf.append("r:I ");
buf.append("r:X ");
}
buf.append("--");
for(int i = 0; i < outD; i++)
{
buf.append(" O");
buf.append(" X");
}
for(int i = 0; i < outR; i++)
{
buf.append(" r:O");
buf.append(" r:X");
}
buf.append(" )");
return buf.toString();
} //}}}
//{{{ clone() method
public Object clone()
{
return new StackEffect(inD,outD,inR,outR);
} //}}}
}

View File

@ -66,7 +66,7 @@
: suspend (--)
! Suspend the current fiber.
! Not really implemented yet.
$initialInterpreterContinuation dup [
$top-level-continuation dup [
call
] [
clear unwind

118
factor/debugger.factor Normal file
View File

@ -0,0 +1,118 @@
!:folding=indent: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.
: exception? ( exception -- boolean )
"java.lang.Throwable" is ;
: print-stack-trace ( exception -- )
[ ] "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" jinvoke
] [
>str
] ifte print ;
: break ( exception -- )
$global [
dup @error
! Called when the interpreter catches an exception.
"break called." print
"" print
":w prints the callstack." print
":j prints the Java stack." print
":r returns to top level." print
":s returns to top level, retaining the data stack." print
":g continues execution (but expect another error)." print
"" print
"ERROR: " write exception.
! XXX: move this to the game core!
$console [
[ t @expanded ] bind
] when*
callstack$ @error-callstack
[
@error-continuation
" DEBUG. " interpreter-loop
! If we end up here, the user just exited the err
! interpreter. If we just call return-from-error
! here, its like :g and this is probably not what
! they wanted. So we :r instead.
:r
] callcc0
] bind ;
: return-from-error ( -- )
"Returning from break." print
f @error-callstack
f @error-flag
f @error ;
: :g ( -- )
! Continues execution from the point of the error. Can be dangerous.
return-from-error
$error-continuation call ;
: :r ( -- )
! Returns to the top level.
return-from-error
!XXX
$initial-interpreter-continuation dup [
call
] [
suspend
] ifte ;
: .s ( -- )
! Prints the contents of the data stack
datastack$ describe ;
: :s ( -- )
! Returns to the top level, retaining the stack.
return-from-error
$initial-interpreter-callstack
callstack@ ;
: :j ( -- )
! Print the stack trace from the exception that caused the
! last break.
$error dup exception? [
print-stack-trace
] [
"Not an exception: " write .
] ifte ;
: :w ( -- )
! Print the current callstack, or the callstack of the last
! error inside an error context.
$error-callstack [ callstack$ ] unless* describe ;

View File

@ -25,14 +25,22 @@
! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
: asm ( word -- assembly )
: apropos ( substring -- )
! Prints all word names that contain the given substring.
words [ 2dup str-contains [ . ] [ drop ] ifte ] each drop ;
: asm ( word -- )
! Prints JVM bytecode disassembly of the given word.
worddef compiled? dup [
intern [ $asm ] bind dup [
print
] [
drop "Not a compiled word." print
] ifte ;
: balance ( code -- effect )
! Push stack effect of the given code quotation.
no-name effect ;
: compile* ( word -- )
$interpreter swap
[ "factor.FactorInterpreter" ] "factor.FactorWord" "compile"
@ -45,32 +53,65 @@
intern compile*
] ifte ;
: compileAll ( -- )
: compile-all ( -- )
"Compiling..." write
words [ compile ] each
" done" print ;
: compiled? ( obj -- boolean )
[ $asm ] bind ;
"factor.compiler.CompiledDefinition" is ;
: compound? ( obj -- boolean )
"factor.FactorCompoundDefinition" is ;
: <compound> ( word def -- worddef )
[ "factor.FactorWord" "factor.Cons" ]
"factor.FactorCompoundDefinition"
jnew ;
: effect ( word -- effect )
! Push stack effect of the given word.
worddef [ ] "factor.FactorWordDefinition"
"getStackEffect" jinvoke ;
: effect>list ( effect -- effect )
[
[ "factor.compiler.StackEffect" "inD" jvar$ ]
[ "factor.compiler.StackEffect" "outD" jvar$ ]
[ "factor.compiler.StackEffect" "inR" jvar$ ]
[ "factor.compiler.StackEffect" "outR" jvar$ ]
] interleave unit cons cons cons ;
: gensym ( -- word )
[ ] "factor.FactorWord" "gensym" jinvoke-static ;
: <word> ( name -- word )
! Creates a new uninternalized word.
[ "java.lang.String" ] "factor.FactorWord" jnew ;
: intern* ( "word" -- word )
dup $ dup [
nip
] [
drop dup $ tuck s@
] ifte ;
: intern ( "word" -- word )
! Returns the top of the stack if it already been interned.
dup word? [ $dict [ intern* ] bind ] unless ;
: missing>f ( word -- word/f )
! Is it the missing word placeholder? Then push f.
dup undefined? [ drop f ] when ;
: no-name ( list -- word )
! Generates an uninternalized word and gives it a compound
! definition created from the given list.
[ gensym dup dup ] dip <compound> define ;
: shuffle? ( obj -- boolean )
"factor.FactorShuffleDefinition" is ;
: 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 ;
@ -79,21 +120,21 @@
: word ( -- word )
! Pushes most recently defined word.
$dict "factor.FactorDictionary" "last" jvar$ ;
$global [ $last ] bind ;
: worddef? (obj -- boolean)
"factor.FactorWordDefinition" is ;
: worddef ( word -- worddef )
intern
"factor.FactorWord" "def" jvar$
missing>f ;
dup worddef? [ intern [ $def ] bind missing>f ] unless ;
: worddefUncompiled ( word -- worddef )
intern
"factor.FactorWord" "uncompiled" jvar$
missing>f ;
: worddef>list ( worddef -- list )
worddef
[ ] "factor.FactorWordDefinition" "toList" jinvoke ;
: words ( -- list )
! Pushes a list of all defined words.
$dict [ ] "factor.FactorDictionary" "toWordList" jinvoke ;
$dict [ uvalues ] bind
[
cdr dup [ drop ] unless
] map ;

View File

@ -26,7 +26,6 @@
! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
: examples/httpd
"/factor/examples/httpd.factor" runResource
"Enter a port number: " write
read >fixnum
"Enter document root (eg, /home/www/): " write
@ -34,5 +33,4 @@
httpd ;
: examples/httpd*
"/factor/examples/httpd.factor" runResource
8888 "/home/slava/ExampleHTTPD/" httpd ;

View File

@ -1,151 +0,0 @@
!:folding=indent: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.
! To make this a bit more useful:
! - URL encoding
! - log with date
! - log user agent
! - add a socket timeout
! - if a directory is requested and URL does not end with /, redirect
! - return more header fields, like Content-Length, Last-Modified, and so on
! - HEAD request
! - make httpdFiletype generic, specify file types in a list of comma pairs
! - basic authentication, using httpdAuth function from a config file
! - when string formatting is added, some code can be simplified
! - use nio to handle multiple requests
! - implement an LSP that does an "apropos" search
: httpdGetPath ( request -- file )
dup ".*\\.\\.*" re-matches [
f
] [
dup [ "GET (.*?)( HTTP.*|)" groups dup [ car ] when ] when
] ifte ;
: httpdResponse (stream msg contentType --)
[ "HTTP/1.0 " over fwrite ] 2dip
[ over fwriteln "Content-type: " over fwriteln ] dip
swap fwriteln ;
: httpdError (stream error --)
"Error: " write dup print
2dup "text/html" httpdResponse
"\n<html><body><h1>" swap "</h1></body></html>" cat3 swap fwriteln ;
: httpdFiletype (filename -- mime-type)
[
[ ".*\.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)
$httpdDocRoot swap
dup "http://.*?(/.*)" groups [ car ] when*
cat2 ;
: httpdPathToAbsolute (path -- absolute)
$httpdDocRoot swap cat2
"Serving " over cat2 print
dup directory? [ "/index.html" cat2 ] when ;
: httpdServeFile (stream argument filename --)
nip
2dup "200 Document follows" swap httpdFiletype httpdResponse
[ "" over fwriteln ] dip
<filebr> swap fcopy ;
: httpdListDirectory (stream directory -- string)
[ "<html><head><title>" over fwrite ] dip
2dup swap fwrite
[ "</title></head><body><h1>" over fwrite ] dip
2dup swap fwrite
[ "</h1><ul>" over fwrite ] dip
directory [
chars>entities
dup directory? [ "/" cat2 ] when
[ "<li><a href=\"" over fwrite ] dip
2dup swap fwrite
[ "\">" over fwrite ] dip
2dup swap fwrite
[ "</a></li>" over fwrite ] dip
drop
] each
"</ul></body></html>" swap fwrite ;
: httpdServeDirectory (stream argument directory --)
dup "/index.html" cat2 dup exists? [
nip httpdServeFile
] [
drop nip
over "200 Document follows" "text/plain" httpdResponse
[ "" over fwriteln ] dip
httpdListDirectory
] ifte ;
: httpdServeScript (stream argument filename --)
<namespace> [ [ @argument @stdio ] dip runFile ] bind ;
: httpdParseObjectName ( filename -- argument filename )
dup "(.*?)\\?(.*)" groups dup [ nip push ] when swap ;
: httpdServeObject (stream filename --)
"Serving " write dup print
httpdParseObjectName
dup exists? [
dup directory? [
httpdServeDirectory
] [
dup ".*\.lhtml" re-matches [
httpdServeScript
] [
httpdServeFile
] ifte
] ifte
] [
2drop "404 Not Found" httpdError
] ifte ;
: httpdRequest (stream request --)
httpdGetPath dup [
httpdUriToPath httpdServeObject
] [
drop "400 Bad request" httpdError
] ifte ;
: httpdClient (socket --)
"Accepted connection from " write dup [ $socket ] bind .
[ dup freadln httpdRequest ] [ fclose ] cleave ;
: httpdLoop (server --)
dup accept httpdClient $httpdQuit [ fclose ] [ httpdLoop ] ifte ;
: httpd (port docroot --)
@httpdDocRoot <server> httpdLoop ;

194
factor/httpd.factor Normal file
View File

@ -0,0 +1,194 @@
!:folding=indent: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.
! To make this a bit more useful:
! - URL encoding
! - log with date
! - log user agent
! - add a socket timeout
! - if a directory is requested and URL does not end with /, redirect
! - return more header fields, like Content-Length, Last-Modified, and so on
! - HEAD request
! - basic authentication, using httpdAuth function from a config file
! - when string formatting is added, some code can be simplified
! - use nio to handle multiple requests
! - implement an LSP that does an "apropos" search
[
[ "html" , "text/html" ]
[ "txt" , "text/plain" ]
[ "gif" , "image/gif" ]
[ "png" , "image/png" ]
[ "jpg" , "image/jpeg" ]
[ "jpeg" , "image/jpeg" ]
[ "jar" , "application/octet-stream" ]
[ "zip" , "application/octet-stream" ]
[ "tgz" , "application/octet-stream" ]
[ "tar.gz" , "application/octet-stream" ]
[ "gz" , "application/octet-stream" ]
] @httpd-extensions
: group1 ( string regex -- string )
groups dup [ car ] when ;
: httpd-response ( msg content-type -- response )
[ "HTTP/1.0 " swap "\nContent-Type: " ] dip "\n" cat5 ;
: httpd-file-header ( filename -- header )
"200 Document follows" swap httpd-filetype httpd-response ;
: httpd-serve-file ( stream filename -- )
2dup httpd-file-header swap fwriteln <filebr> swap fcopy ;
: httpd-log-error ( error -- )
"Error: " swap cat2 print ;
: httpd-error-body ( error -- body )
"\n<html><body><h1>" swap "</h1></body></html>" cat3 ;
: httpd-error ( stream error -- )
dup httpd-log-error
[ "text/html" httpd-response ] [ httpd-error-body ] cleave
cat2
swap fwriteln ;
: httpd-response-write ( stream msg content-type -- )
httpd-response swap fwriteln ;
: httpd-file-extension ( filename -- extension )
".*\\.(.*)" group1 ;
: httpd-filetype ( filename -- mime-type )
httpd-file-extension $httpd-extensions assoc
[ "text/plain" ] unless* ;
: httpd-url>path ( uri -- path )
dup "http://.*?(/.*)" group1 dup [
nip
] [
drop
] ifte
$httpd-doc-root swap cat2 ;
: httpd-file>html ( filename -- ... )
"<li><a href=\"" swap
!dup directory? [ "/" cat2 ] when
chars>entities
"\">" over "</a></li>" ;
: httpd-directory>html ( directory -- html )
directory [ httpd-file>html ] map cat ;
: httpd-directory-header ( stream directory -- )
"200 Document follows" "text/html" httpd-response fwriteln ;
: httpd-list-directory ( stream directory -- )
2dup httpd-directory-header [
"<html><head><title>" swap
"</title></head><body><h1>" over
"</h1><ul>" over
httpd-directory>html
"</ul></body></html>"
] cons expand cat swap fwrite ;
: httpd-serve-directory ( stream directory -- )
dup "/index.html" cat2 dup exists? [
nip httpd-serve-file
] [
drop httpd-list-directory
] ifte ;
: httpd-serve-script ( stream argument filename -- )
<namespace> [ [ @argument @stdio ] dip runFile ] bind ;
: httpd-parse-object-name ( filename -- argument filename )
dup "(.*?)\\?(.*)" groups dup [ nip call ] when swap ;
: httpd-serve-static ( stream filename -- )
dup exists? [
dup directory? [
httpd-serve-directory
] [
httpd-serve-file
] ifte
] [
drop "404 Not Found" httpd-error
] ifte ;
: httpd-serve-object ( stream argument filename -- )
dup ".*\\.lhtml" re-matches [
httpd-serve-script
] [
nip httpd-serve-static
] ifte ;
: httpd-serve-log ( filename -- )
"Serving " swap cat2 print ;
: httpd-get-request ( stream url -- )
httpd-url>path dup httpd-serve-log
httpd-parse-object-name httpd-serve-object ;
: httpd-get-path ( request -- file )
"GET (.*?)( HTTP.*|)" group1 ;
: httpd-get-secure-path ( path -- path )
dup [
httpd-get-path dup [
dup ".*\\.\\.*" re-matches [ drop f ] when
] [
drop f
] ifte
] [
drop f
] ifte ;
: httpd-request ( stream request -- )
httpd-get-secure-path dup [
httpd-get-request
] [
drop "400 Bad request" httpd-error
] ifte ;
: httpd-client-log ( socket -- )
"Accepted connection from " write [ $socket ] bind . ;
: httpd-client ( socket -- )
dup httpd-client-log
dup freadln [ httpd-request ] when* ;
: httpd-loop ( server -- )
[
$httpd-quit not
] [
dup accept dup httpd-client fclose
] while ;
: httpd ( port docroot -- )
@httpd-doc-root <server> httpd-loop ;

141
factor/inspector.factor Normal file
View File

@ -0,0 +1,141 @@
!:folding=indent: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.
: max-str-length ( list -- len )
! Returns the length of the longest string in the given
! list.
0 swap [ str-length max ] each ;
: pad-string ( len str -- str )
str-length - spaces ;
: words. (--)
! Print all defined words.
words [ . ] each ;
: vars. ( -- )
! Print a list of defined variables.
uvars [ print ] each ;
: value/tty ( max [ name , value ] -- ... )
uncons [ dup [ pad-string ] dip ": " ] dip unparse "\n" ;
: values/tty ( -- ... )
! Apply 'expand' or 'str-expand' to this word.
uvars max-str-length
uvalues [ over [ value/tty ] dip ] each drop ;
: value/html ( [ name , value ] -- ... )
uncons [
[ "<tr><th align=\"left\">" ] dip
"</th><td><a href=\"inspect.lhtml?" over "\">"
] dip
unparse chars>entities
"</a></td></tr>" ;
: values/html ( -- ... )
! Apply 'expand' or 'str-expand' to this word.
uvalues [ value/html ] each ;
: inspecting ( obj -- namespace )
dup has-namespace? [ <objnamespace> ] unless ;
: describe* ( obj quot -- )
! Print an informational header about the object, and print
! all values in its object namespace.
swap inspecting [ str-expand ] bind print ;
: describe ( obj -- )
[
[ worddef? ] [ see ]
[ stack? ] [ stack>list print-numbered-list ]
[ string? ] [ print ]
[ drop t ] [
"OBJECT: " write dup .
[
"CLASS : " write dup class-of print
"--------" print
[ values/tty ] describe*
] when*
]
] cond ;
: describe/html ( obj -- )
[
[ worddef? ] [ see/html ]
[ string? ] [
"<pre>" print chars>entities print "</pre>" print
]
[ drop t ] [
"<table><tr><th align=\"left\">OBJECT:</th><td>" print
dup unparse chars>entities write
"</td></tr>" print
[
"<tr><th align=\"left\">CLASS:</th><td>" write
dup class-of print
"</td></tr>" print
"<tr><td colspan=\"2\"><hr></td></tr>" print
[ values/html ] describe*
] when*
"</table>" print
]
] cond ;
: object-path ( list -- object )
! An object path is a list of strings. Each string is a
! variable name in the object namespace at that level.
! Returns f if any of the objects are not set.
dup [
unswons $ dup [
! Defined.
inspecting [ object-path ] bind
] [
! Undefined. Just return f.
2drop f
] ifte
] [
! Current object.
drop $this [ $namespace ] unless*
] ifte ;
: inspect ( obj -- )
! Display the inspector for the object, and start a new
! REPL bound to the object's namespace.
inspecting dup describe
"--------" print
! Start a REPL, only if the object is not the dictionary.
dup $dict = [
"Cannot enter into dictionary. Use 'see' word." print
] [
"exit - exit one level of inspector." print
"suspend - return to top level." print
dup [
" " swap unparse " " cat3 interpreter-loop
] bind
] ifte ;

View File

@ -25,136 +25,58 @@
! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
: exception? (exception -- boolean)
"java.lang.Throwable" is ;
0 @history-count
: printStackTrace (exception --)
[ ] "java.lang.Throwable" "printStackTrace" jinvoke ;
: exit (--)
$global [ t @quit-flag ] bind ;
: 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" jinvoke
] [
>str
] ifte print ;
: break (exception --)
dup @error
! Called when the interpreter catches an exception.
"break called." print
"" print
":w prints the callstack." print
":j prints the Java stack." print
":r returns to top level." print
":s returns to top level, retaining the data stack." print
":g continues execution (but expect another error)." print
"" print
"ERROR: " write exception.
:w
callstack$ @errorCallStack
[
@errorContinuation
interpreterLoop
! If we end up here, the user just exited the err interpreter.
! If we just call returnFromError here, its like :g and this
! is probably not what they wanted. So we :r instead.
:r
] callcc0 ;
: returnFromError (--)
"Returning from break." print
f @errorCallStack
f @errorFlag
f @error ;
: :g (--)
! Continues execution from the point of the error. Can be dangerous.
returnFromError
$errorContinuation call ;
: :r (--)
! Returns to the top level.
returnFromError
!XXX
$initialInterpreterContinuation dup [
call
] [
suspend
] ifte ;
: :s (--)
! Returns to the top level, retaining the stack.
returnFromError
$initialInterpreterCallStack callstack@ ;
: :j (--)
! Print the stack trace from the exception that caused the last break.
$error dup exception? [
printStackTrace
] [
"Not an exception: " write .
] ifte ;
: :w (--)
! Print the current callstack, or the callstack of the last error inside an
! error context.
$errorCallStack dup [
drop callstack$
] unless . ;
: printPrompt (--)
$errorFlag " err> " " ok> " ? write ;
: interpreterLoop (--)
printPrompt read [
eval
$quitFlag [ interpreterLoop ] unless
] when* ;
: initialInterpreterLoop (--)
! Run the stand-alone interpreter
: print-banner ( -- )
"Factor " $version cat2 print
"Copyright (C) 2003, 2004 Slava Pestov" print
"Enter ``help'' for help." print
"Enter ``exit'' to exit." print
"Enter ``exit'' to exit." print ;
: history+ ( cmd -- )
$history 2dup contains [ 2drop ] [ cons @history ] ifte
"history-count" succ@ ;
: history ( -- )
"X redo -- evaluate the expression with number X." print
"X re-edit -- edit the expression with number X." print
$history print-numbered-list ;
: get-history ( index -- )
$history reverse swap get ;
: redo ( index -- )
get-history [ . ] [ eval ] cleave ;
: re-edit ( index -- )
get-history edit ;
: print-prompt ( prompt -- )
write $history-count write "] " write ;
: interpreter-loop ( prompt -- )
dup >r print-prompt read [
[ history+ ] [ eval ] cleave
$global [ $quit-flag ] bind [
rdrop
$global [ f @quit-flag ] bind
] [
r> interpreter-loop
] ifte
] when* ;
: initial-interpreter-loop (--)
! Run the stand-alone interpreter
print-banner
! Used by :r
[ @initialInterpreterContinuation ] callcc0
[ @initial-interpreter-continuation ] callcc0
! Used by :s
! We use the slightly redundant 'call' to push the current callframe.
[ callstack$ @initialInterpreterCallStack ] call
interpreterLoop ;
: words. (--)
! Print all defined words.
words [ . ] each ;
: see (word --)
dup worddefUncompiled [
(word -- worddef word)
dup [
worddefUncompiled dup shuffle? "~<< " ": " ? write
] dip
(worddef word -- worddef)
write "\n " write
dup >str write
shuffle? " >>~\n" " ;\n" ? write
] [
"Not defined: " write print
] ifte ;
: vars. (--)
! Print a list of defined variables.
vars [ . ] each ;
: .s (--)
! Prints the contents of the data stack
datastack$ . ;
[ callstack$ @initial-interpreter-callstack ] call
" " interpreter-loop ;
: stats ( -- )
"Cons: " write
@ -167,28 +89,24 @@
: 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
"clear -- clear datastack."
".s -- print datastack."
". -- print top of datastack."
"" print
"= Dynamic, interpreted, stack-based scripting language" print
"= Arbitrary precision math, ratio math" print
"= First-class, higher-order, and anonymous functions" print
"= Prototype-based object system" print
"= Continuations" print
"= Tail call optimization" print
"= Rich set of primitives based on recursion" print
"" print
"Some basic commands:" print
"clear -- clear stack." print
".s -- print stack." print
". -- print top of stack." print
"vars. -- list all variables." print
"values. -- list all variables." print
"inspect -- list all variables bound on object at top of stack." print
"$variable . -- show value of variable." print
"" print
"words. -- list all words." print
"\"str\" apropos -- list all words whose name contains str." print
"\"word\" see -- show definition of word." print
"" print
"[ expr ] balance . -- show stack effect of expression." print
"" print
"history -- list previously entered expresions." print
"X redo -- redo expression number X from history list." print
"" print
"stats -- interpreter statistics." print
"exit -- exit the interpreter." print
"" print ;

View File

@ -25,9 +25,42 @@
! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
!
! List manipulation primitives
!
: array>list ( array -- list )
[ [ "java.lang.Object" ] ] "factor.Cons" "fromArray"
jinvoke-static ;
: car ([ car , cdr ] -- car)
|factor.Cons |car jvar$ ;
: cdr ([ car , cdr ] -- cdr)
|factor.Cons |cdr jvar$ ;
: cons (car cdr -- [ car , cdr ])
[ |java.lang.Object |java.lang.Object ] |factor.Cons jnew ;
: cons? (list -- boolean)
|factor.Cons is ;
: rplaca ( A [ B , C ] -- [ A , C ] )
! Destructive!
"factor.Cons" "car" jvar@ ;
: rplacd ( A [ B , C ] -- [ B , A ] )
! Destructive!
"factor.Cons" "cdr" jvar@ ;
!
! List manipulation library
!
: 2list (a b -- [ a b ])
unit cons ;
: 3list ( a b c -- [ a b c ] )
2list cons ;
: 2rlist (a b -- [ b a ])
swap unit cons ;
@ -41,10 +74,6 @@
! Adds the list to the end of the list stored in the given variable.
dup [ $ swap append ] dip @ ;
: array>list ( array -- list )
[ [ "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.
dup [ $ swap add ] dip @ ;
@ -63,11 +92,19 @@
2drop f
] ifte ;
: car ([ car , cdr ] -- car)
|factor.Cons |car jvar$ ;
: cdr ([ car , cdr ] -- cdr)
|factor.Cons |cdr jvar$ ;
: assoc$ (key alist -- value)
! Looks up the key in the given variable alist. A variable
! alist is a list of comma pairs, the car of each pair is a
! variable name, the cdr is the value.
dup [
2dup car car $ = [
nip car cdr
] [
cdr assoc$
] ifte
] [
2drop f
] ifte ;
: caar (list -- caar)
car car ;
@ -81,18 +118,24 @@
: cddr (list -- cddr)
cdr cdr ;
: cloneList (list -- list)
! Returns a new list where each element is a clone of the elements of
! the given list.
dup [ [ ] "factor.Cons" "deepClone" jinvoke ] when ;
: clone-list-iter ( result list -- last [ ] )
[
dup cons?
] [
uncons [ unit tuck [ rplacd ] dip ] dip
] while ;
: cons (car cdr -- [ car , cdr ])
[ |java.lang.Object |java.lang.Object ] |factor.Cons jnew ;
: clone-list (list -- list)
dup [
uncons [ unit dup ] dip clone-list-iter swap rplacd
] when ;
: contains (elem list -- boolean)
: contains ( elem list -- remainder )
! If the list contains elem, return the remainder of the
! list, starting from the cell whose car is elem.
dup [
2dup car = [
2drop t
nip
] [
cdr contains
] ifte
@ -102,21 +145,17 @@
: cons@ (x var --)
! Prepends x to the list stored in var.
dup [ $ cons ] dip @ ;
tuck $ cons s@ ;
: count (n -- [ 1 2 3 ... n ])
[ [ ] times* ] cons expand ;
: swons@ (var x --)
! Prepends x to the list stored in var.
over $ cons s@ ;
: get (list n -- list[n])
[ cdr ] times car ;
: last* ( list -- last )
! Pushes last cons of the list.
[ dup cdr ] [ cdr ] while ;
[ dup cdr cons? ] [ cdr ] while ;
: last ( list -- last )
! Pushes last element of the list.
@ -125,37 +164,88 @@
: length (list -- length)
0 swap [ drop succ ] each ;
: list (list[0] ... list[n] n -- list)
[ ] swap [ cons ] times ;
: list? ( list -- boolean )
dup pair? [ cdr list? ] [ f ] ifte ;
! A list is either f, or a cons cell whose cdr is a list.
dup [
dup cons? [
cdr list?
] [
drop f
] ifte
] [
drop t
] ifte ;
: nappend ( [ list1 ] [ list2 ] -- [ list1 list2 ] )
! Destructive on list1!
over [ last* rplacd ] when* ;
over [ over last* rplacd ] [ nip ] ifte ;
: pair? (list -- boolean)
|factor.Cons is ;
~<< partition-iterI
R1 R2 A D C -- A C r:R1 r:R2 r:A r:D r:C >>~
~<< partition-iterT{
r:R1 r:R2 r:A r:D r:C -- A R1 r:R1 r:R2 r:D r:C >>~
~<< }partition-iterT
R1 r:R1X r:R2 r:D r:C -- R1 R2 D C >>~
~<< partition-iterF{
r:R1 r:R2 r:A r:D r:C -- A R2 r:R1 r:R2 r:D r:C >>~
~<< }partition-iterF
R2 r:R1 r:R2X r:D r:C -- R1 R2 D C >>~
: partition-iter ( ref ret1 ret2 list combinator -- ret1 ret2 )
over [
! Note this ifte must be in tail position!
[ uncons ] dip partition-iterI [ dup ] 2dip call [
partition-iterT{ cons }partition-iterT partition-iter
] [
partition-iterF{ cons }partition-iterF partition-iter
] ifte
] [
2drop
] ifte ;
: partition ( ref list combinator -- list1 list2 )
[ ] [ ] 2swap partition-iter rot drop ;
: 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@ ;
: sort ( list comparator -- sorted )
over [
! Partition
dup [ [ uncons dupd ] dip partition ] dip
! Recurse
tuck sort [ sort ] dip
! Combine
swapd cons append
] [
drop
] ifte ;
: swons (cdr car -- [ car , cdr ])
swap [ |java.lang.Object |java.lang.Object ]
|factor.Cons jnew ;
swap cons ;
: swons@ (var x --)
! Prepends x to the list stored in var.
over $ cons s@ ;
: uncons ([ car , cdr ] -- car cdr)
dup car swap cdr ;
: unique ( elem list -- list )
! Cons elem onto list if its not already there.
2dup contains [
nip
] [
cons
] ifte ;
: unique@ ( elem var -- )
tuck $ unique s@ ;
: unit (a -- [ a ])
f cons ;

View File

@ -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:
@ -28,9 +28,16 @@
: 0= (x -- boolean)
0 = ;
: 0>f ( obj -- oj )
! If 0 a the top of the stack, turn it into f.
dup 0 = [ drop f ] when ;
: 1= (x -- boolean)
1 = ;
: number? (obj -- boolean)
"java.lang.Number" is ;
: fixnum? (obj -- boolean)
"java.lang.Integer" is ;
@ -58,6 +65,9 @@
[ "java.lang.Number" "java.lang.Number" ] "factor.FactorMath" "add"
jinvoke-static ;
: v+ ( A B -- A+B )
[ + ] 2map ;
: +@ (num var --)
dup [ $ + ] dip @ ;
@ -65,6 +75,10 @@
[ "java.lang.Number" "java.lang.Number" ] "factor.FactorMath" "subtract"
jinvoke-static ;
: v- ( A B -- A-B )
[ - ] 2map ;
: -@ (num var --)
dup [ $ swap - ] dip @ ;
@ -72,6 +86,13 @@
[ "java.lang.Number" "java.lang.Number" ] "factor.FactorMath" "multiply"
jinvoke-static ;
: v* ( A B -- A*B )
[ * ] 2map ;
: v. ( A B -- A.B )
! Dot product.
v* 0 swap [ + ] each ;
: *@ (num var --)
dup [ $ * ] dip @ ;
@ -79,6 +100,9 @@
[ "java.lang.Number" "java.lang.Number" ] "factor.FactorMath" "divide"
jinvoke-static ;
: v/ ( A B -- A/B )
[ / ] 2map ;
: /@ (num var --)
dup [ $ / ] dip @ ;
@ -97,10 +121,20 @@
: and (a b -- a&b)
f ? ;
: gcd ( a b -- c )
[ "java.lang.Number" "java.lang.Number" ]
"factor.FactorMath" "gcd" jinvoke-static ;
: mag2 (x y -- mag)
! Returns the magnitude of the vector (x,y).
sq swap sq + sqrt ;
: max ( x y -- z )
2dup > -rot ? ;
: min ( x y -- z )
2dup < -rot ? ;
: neg (x -- -x)
0 swap - ;
@ -120,14 +154,11 @@
: pred (n -- n-1)
1 - ;
: round ( x y -- x^y )
[ "double" "double" ] "java.lang.Math" "pow" jinvoke-static ;
: succ (n -- nsucc)
1 + ;
: pred@ (var --)
dup $ 1 - s@ ;
dup $ pred s@ ;
: or (a b -- a|b)
t swap ? ;
@ -135,6 +166,13 @@
: recip (x -- 1/x)
1 swap / ;
: rem ( x y -- remainder )
[ "double" "double" ] "java.lang.Math" "IEEEremainder"
jinvoke-static ;
: round ( x to -- y )
dupd rem - ;
: sq (x -- x^2)
dup * ;
@ -142,7 +180,7 @@
[ "double" ] "java.lang.Math" "sqrt" jinvoke-static ;
: succ@ (var --)
dup $ 1 + s@ ;
dup $ succ s@ ;
: deg2rad (degrees -- radians)
$pi * 180 / ;

View File

@ -30,6 +30,9 @@
[ "java.lang.Object" "java.lang.Object" ]
"factor.FactorLib" "equal" jinvoke-static ;
: class-of ( obj -- class )
[ ] "java.lang.Object" "getClass" jinvoke ;
: clone (obj -- obj)
[ ] "factor.PublicCloneable" "clone" jinvoke ;
@ -69,18 +72,22 @@
: exit* (code --)
[ |int ] |java.lang.System |exit jinvoke-static ;
: exit (--)
0 exit* ;
: millis (-- millis)
! Pushes the current time, in milliseconds.
[ ] |java.lang.System |currentTimeMillis jinvoke-static
>bignum ;
: stack? ( obj -- ? )
"factor.FactorArrayStack" is ;
: stack>list (stack -- list)
! Turns a callstack or datastack object into a list.
[ ] "factor.FactorArrayStack" "toList" jinvoke ;
: system-property ( name -- value )
[ "java.lang.String" ] "java.lang.System" "getProperty"
jinvoke-static ;
: time (code --)
! Evaluates the given code and prints the time taken to execute it.
millis swap dip millis -- . ;
millis >r call millis r> - . ;

View File

@ -28,13 +28,16 @@
: s@ ( variable value -- )
swap @ ;
: has-namespace? ( a -- boolean )
"factor.FactorObject" is ;
: lazy ( var [ a ] -- value )
! If the value of the variable is f, set the value to the result of
! evaluating [ a ].
! If the value of the variable is f, set the value to the
! result of evaluating [ a ].
over $ [ drop $ ] [ dip dupd @ ] ifte ;
: namespace? ( a -- boolean )
|factor.FactorNamespace is ;
"factor.FactorNamespace" is ;
: <namespace> (-- namespace)
$namespace [ |factor.FactorNamespace ] |factor.FactorNamespace
@ -54,7 +57,8 @@
over [ bind ] dip ;
: import ( class pairs -- )
! Import some static variables from a Java class into the current namespace.
! Import some static variables from a Java class into the
! current namespace.
$namespace [ |java.lang.String |factor.Cons ]
|factor.FactorNamespace |importVars
jinvoke ;
@ -62,10 +66,17 @@
: vars ( -- list )
$namespace [ ] |factor.FactorNamespace |toVarList jinvoke ;
: values ( -- list )
$namespace [ ] |factor.FactorNamespace |toValueList
jinvoke ;
: uvalues ( -- list )
values [ car uvar? ] subset ;
: uvar? ( name -- )
[ "namespace" "parent" ] contains not ;
[ "namespace" "parent" "this" ] contains not ;
: uvars ( -- list )
! Does not include "namespace" and "parent" variables; ie, all user-defined
! variables in given namespace.
! Does not include "namespace" and "parent" variables; ie,
! all user-defined variables in given namespace.
vars [ uvar? ] subset ;

View File

@ -28,15 +28,28 @@
: parse ( string -- list )
f swap <sreader> parse* ;
: compile-call ( [ X ] -- X )
no-name dup compile execute ;
: eval ( "X" -- X )
parse call ;
parse $compile-toplevel [ compile-call ] [ call ] ifte ;
: eval-compile ( "X" -- X )
parse no-name word compile word execute ;
: runFile ( path -- )
dup <freader> parse* call ;
: unparse ( X -- "X" )
[ |java.lang.Object ] |factor.FactorJava |factorTypeToString
[ |java.lang.Object ] |factor.FactorParser |unparse
jinvoke-static ;
: . ( expr -- )
unparse print ;
: parse-number ( str -- number )
parse dup length 1 = [
car dup number? [ drop f ] unless
] [
drop f
] ifte ;

176
factor/prettyprint.factor Normal file
View File

@ -0,0 +1,176 @@
!:folding=indent: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.
4 @indent
: <prettyprint-token> ( string -- token )
dup <namespace> [
@name
t @prettyprint-token
] extend tuck s@ ;
: prettyprint-token? ( token -- token? )
dup has-namespace? [
[ $prettyprint-token ] bind
] [
drop f
] ifte ;
: prettyprint-indent ( indent -- indent )
dup spaces write ;
: prettyprint-newline/space ( indent ? -- indent )
[ "\n" write prettyprint-indent ] [ " " write ] ifte ;
: prettyprint-indent-params ( indent obj -- indent ? ? name )
[
$indent+ [ $indent + ] when
$indent- [ $indent - ] when
$-indent [ $indent - t ] [ f ] ifte
$newline
$name
] bind ;
: prettyprint-token ( indent obj -- indent )
prettyprint-indent-params
[
[
"\n" write
prettyprint-indent
] when
] 2dip
write prettyprint-newline/space ;
: prettyprint-unparsed ( indent unparse -- indent )
dup "\n" = [
drop "\n" write prettyprint-indent
] [
write " " write
] ifte ;
: [prettyprint-tty] ( indent obj -- indent )
dup prettyprint-token? [
prettyprint-token
] [
unparse prettyprint-unparsed
] ifte ;
: prettyprint-html-unparse ( obj -- unparse )
dup unparse dup "\n" = [
nip
] [
swap word? [
"<a href=\"see.lhtml?" swap "\">" over "</a>" cat5
] [
chars>entities
] ifte
] ifte ;
: [prettyprint-html] ( indent obj -- indent )
dup prettyprint-token? [
prettyprint-token
] [
prettyprint-html-unparse prettyprint-unparsed
] ifte ;
: prettyprint-list* ( quot list -- )
! Pretty-print a list, without [ and ].
[
over [
prettyprint*
] dip
] each
! Drop the quotation
drop ;
: prettyprint-list ( quot list before after -- )
! Apply the quotation to 'before', call prettyprint* on
! 'list', and apply the quotation to 'after'.
swapd [
[
swap dup [
call
] dip
] dip
swap dup [
swap prettyprint-list*
] dip
] dip
swap call ;
: prettyprint* ( quot obj -- )
[
[ not ] [ swap call ]
[ list? ] [ $[ $] prettyprint-list ]
[ compound? ] [ worddef>list $: $; prettyprint-list ]
[ compiled? ] [ worddef>list $: $; prettyprint-list ]
[ shuffle? ] [ worddef>list $~<< $>>~ prettyprint-list ]
[ drop t ] [ swap call ]
] cond ;
: prettyprint-tty ( list -- )
0 [ [prettyprint-tty] ] rot prettyprint* drop ;
: prettyprint-html ( list -- )
0 [ [prettyprint-html] ] rot prettyprint* drop ;
: see ( word -- )
worddef prettyprint-tty ;
: see/html ( word -- )
"<pre>" print
worddef prettyprint-html
"</pre>" print ;
!!!
"[" <prettyprint-token> [
t @indent+
t @newline
] bind
"]" <prettyprint-token> [
t @-indent
] bind
":" <prettyprint-token> [
t @indent+
] bind
";" <prettyprint-token> [
t @indent-
t @newline
] bind
"~<<" <prettyprint-token> [
t @indent+
] bind
">>~" <prettyprint-token> [
t @indent-
t @newline
] bind

View File

@ -32,7 +32,7 @@ package factor.primitives;
import factor.compiler.*;
import factor.*;
import java.lang.reflect.*;
import java.util.Set;
import java.util.Map;
import org.objectweb.asm.*;
public class Bind extends FactorWordDefinition
@ -55,40 +55,26 @@ public class Bind extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws Exception
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler state) throws Exception
{
state.ensure(state.datastack,2);
LocalAllocator.FlowObject quot
= (LocalAllocator.FlowObject)
state.datastack.pop();
FlowObject quot = (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;
quot.getStackEffect(recursiveCheck);
} //}}}
//{{{ compileCallTo() method
//{{{ compileImmediate() method
/**
* Compile a call to this word. Returns maximum JVM stack use.
*/
public int compileCallTo(
public int compileImmediate(
CodeVisitor mw,
LocalAllocator allocator,
Set recursiveCheck)
FactorCompiler compiler,
RecursiveState recursiveCheck)
throws Exception
{
LocalAllocator.FlowObject quot = (LocalAllocator.FlowObject)
allocator.datastack.pop();
FlowObject quot = (FlowObject)compiler.datastack.pop();
// store namespace on callstack
mw.visitVarInsn(ALOAD,0);
@ -101,11 +87,11 @@ public class Bind extends FactorWordDefinition
"factor/FactorCallFrame",
"namespace",
"Lfactor/FactorNamespace;");
allocator.pushR(mw);
compiler.pushR(mw);
// set new namespace
mw.visitInsn(DUP);
allocator.pop(mw);
compiler.pop(mw);
FactorJava.generateFromConversion(mw,FactorNamespace.class);
mw.visitFieldInsn(PUTFIELD,
"factor/FactorCallFrame",
@ -115,7 +101,7 @@ public class Bind extends FactorWordDefinition
int maxJVMStack = quot.compileCallTo(mw,recursiveCheck);
// restore namespace from callstack
allocator.popR(mw);
compiler.popR(mw);
mw.visitFieldInsn(PUTFIELD,
"factor/FactorCallFrame",
"namespace",

View File

@ -32,7 +32,7 @@ package factor.primitives;
import factor.compiler.*;
import factor.*;
import java.lang.reflect.*;
import java.util.Set;
import java.util.Map;
import org.objectweb.asm.*;
public class Call extends FactorWordDefinition
@ -52,39 +52,25 @@ public class Call extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws Exception
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler 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;
FlowObject quot = (FlowObject)state.datastack.pop();
quot.getStackEffect(recursiveCheck);
} //}}}
//{{{ compileCallTo() method
//{{{ compileImmediate() method
/**
* Compile a call to this word. Returns maximum JVM stack use.
*/
public int compileCallTo(
public int compileImmediate(
CodeVisitor mw,
LocalAllocator allocator,
Set recursiveCheck)
FactorCompiler compiler,
RecursiveState recursiveCheck)
throws Exception
{
LocalAllocator.FlowObject quot = (LocalAllocator.FlowObject)
allocator.datastack.pop();
FlowObject quot = (FlowObject)compiler.datastack.pop();
return quot.compileCallTo(mw,recursiveCheck);
} //}}}
}

View File

@ -60,26 +60,25 @@ public class Choice extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(java.util.Set recursiveCheck,
LocalAllocator state) throws FactorStackException
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler state) throws FactorStackException
{
state.ensure(state.datastack,3);
state.pushChoice();
return new StackEffect(3,1,0,0);
state.pushChoice(recursiveCheck);
} //}}}
//{{{ compileCallTo() method
/**
* Compile a call to this word. Returns maximum JVM stack use.
*/
/* public int compileCallTo(
public int compileCallTo(
CodeVisitor mw,
LocalAllocator allocator,
java.util.Set recursiveCheck)
FactorCompiler compiler,
RecursiveState recursiveCheck)
throws Exception
{
allocator.pushChoice();
compiler.pushChoice(recursiveCheck);
return 0;
} */ //}}}
} //}}}
}

View File

@ -31,7 +31,7 @@ package factor.primitives;
import factor.compiler.*;
import factor.*;
import java.util.Set;
import java.util.Map;
public class Define extends FactorWordDefinition
{
@ -46,32 +46,38 @@ public class Define extends FactorWordDefinition
throws Exception
{
FactorDataStack datastack = interp.datastack;
FactorDictionary dict = interp.dict;
// handle old define syntax
Object obj = datastack.pop();
Object def = datastack.pop();
Object name = datastack.pop();
core(interp,name,def);
} //}}}
FactorWord newWord = interp.dict.intern(
(String)datastack.pop(String.class));
if(obj instanceof Cons)
//{{{ core() method
public static void core(FactorInterpreter interp,
Object name, Object def) throws Exception
{
obj = new FactorCompoundDefinition(
newWord,(Cons)obj);
// name: either a string or a word
FactorWord newWord;
if(name instanceof FactorWord)
newWord = (FactorWord)name;
else
newWord = interp.intern((String)name);
if(def instanceof Cons)
{
def = new FactorCompoundDefinition(
newWord,(Cons)def);
}
FactorWordDefinition def = (FactorWordDefinition)obj;
newWord.define(def);
dict.last = newWord;
newWord.define((FactorWordDefinition)def);
interp.last = newWord;
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws FactorStackException
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler state) throws FactorStackException
{
state.ensure(state.datastack,2);
state.pop(null);
state.pop(null);
return new StackEffect(2,0,0,0);
} //}}}
}

View File

@ -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.lang.reflect.*;
import java.util.Set;
import org.objectweb.asm.*;
public class Execute extends FactorWordDefinition
{
//{{{ Execute constructor
public Execute(FactorWord word)
{
super(word);
} //}}}
//{{{ eval() method
public void eval(FactorInterpreter interp)
throws Exception
{
interp.eval(interp.datastack.pop());
} //}}}
}

View File

@ -31,7 +31,7 @@ package factor.primitives;
import factor.compiler.*;
import factor.*;
import java.util.Set;
import java.util.Map;
public class Get extends FactorWordDefinition
{
@ -58,12 +58,11 @@ public class Get extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws FactorStackException
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler state) throws FactorStackException
{
state.ensure(state.datastack,1);
state.pop(null);
state.push(null);
return new StackEffect(1,1,0,0);
} //}}}
}

View File

@ -32,7 +32,7 @@ package factor.primitives;
import factor.compiler.*;
import factor.*;
import java.lang.reflect.*;
import java.util.Set;
import java.util.Map;
import org.objectweb.asm.*;
public class JInvoke extends FactorWordDefinition
@ -57,8 +57,8 @@ public class JInvoke extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws Exception
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler state) throws Exception
{
state.ensure(state.datastack,4);
Object clazz = state.popLiteral();
@ -75,31 +75,31 @@ public class JInvoke extends FactorWordDefinition
(String)name,
(Cons)args);
boolean returnValue = method.getReturnType() == Void.TYPE;
boolean returnValue = (method.getReturnType() != Void.TYPE);
int params = method.getParameterTypes().length;
state.consume(state.datastack,params);
if(returnValue)
state.push(null);
return new StackEffect(
4 + method.getParameterTypes().length,
returnValue ? 0 : 1,0,0);
}
else
return null;
throw new FactorCompilerException("Cannot deduce stack effect of " + word + " with non-literal arguments");
} //}}}
//{{{ compileCallTo() method
//{{{ compileImmediate() method
/**
* Compile a call to this word. Returns maximum JVM stack use.
* XXX: does not use factor type system conversions.
*/
public int compileCallTo(
public int compileImmediate(
CodeVisitor mw,
LocalAllocator allocator,
Set recursiveCheck)
FactorCompiler compiler,
RecursiveState recursiveCheck)
throws Exception
{
Object _method = allocator.popLiteral();
Object _clazz = allocator.popLiteral();
Object _args = allocator.popLiteral();
Object _method = compiler.popLiteral();
Object _clazz = compiler.popLiteral();
Object _args = compiler.popLiteral();
if(_method instanceof String &&
_clazz instanceof String &&
(_args == null || _args instanceof Cons))
@ -116,10 +116,10 @@ public class JInvoke extends FactorWordDefinition
FactorJava.generateToConversionPre(mw,returnType);
allocator.pop(mw);
compiler.pop(mw);
FactorJava.generateFromConversion(mw,cls);
allocator.generateArgs(mw,args.length,args);
compiler.generateArgs(mw,args.length,args);
int opcode;
if(cls.isInterface())
@ -135,7 +135,7 @@ public class JInvoke extends FactorWordDefinition
if(returnType != Void.TYPE)
{
FactorJava.generateToConversion(mw,returnType);
allocator.push(mw);
compiler.push(mw);
}
return 4 + args.length;

View File

@ -32,7 +32,7 @@ package factor.primitives;
import factor.compiler.*;
import factor.*;
import java.lang.reflect.*;
import java.util.Set;
import java.util.Map;
import org.objectweb.asm.*;
public class JInvokeStatic extends FactorWordDefinition
@ -56,8 +56,8 @@ public class JInvokeStatic extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws Exception
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler state) throws Exception
{
state.ensure(state.datastack,3);
Object clazz = state.popLiteral();
@ -73,31 +73,31 @@ public class JInvokeStatic extends FactorWordDefinition
(String)name,
(Cons)args);
boolean returnValue = method.getReturnType() == Void.TYPE;
boolean returnValue = (method.getReturnType() != Void.TYPE);
int params = method.getParameterTypes().length;
state.consume(state.datastack,params);
if(returnValue)
state.push(null);
return new StackEffect(
3 + method.getParameterTypes().length,
returnValue ? 0 : 1,0,0);
}
else
return null;
throw new FactorCompilerException("Cannot deduce stack effect of " + word + " with non-literal arguments");;
} //}}}
//{{{ compileCallTo() method
//{{{ compileImmediate() method
/**
* Compile a call to this word. Returns maximum JVM stack use.
* XXX: does not use factor type system conversions.
*/
public int compileCallTo(
public int compileImmediate(
CodeVisitor mw,
LocalAllocator allocator,
Set recursiveCheck)
FactorCompiler compiler,
RecursiveState recursiveCheck)
throws Exception
{
Object _method = allocator.popLiteral();
Object _clazz = allocator.popLiteral();
Object _args = allocator.popLiteral();
Object _method = compiler.popLiteral();
Object _clazz = compiler.popLiteral();
Object _args = compiler.popLiteral();
if(_method instanceof String &&
_clazz instanceof String &&
(_args == null || _args instanceof Cons))
@ -114,7 +114,7 @@ public class JInvokeStatic extends FactorWordDefinition
FactorJava.generateToConversionPre(mw,returnType);
allocator.generateArgs(mw,args.length,args);
compiler.generateArgs(mw,args.length,args);
mw.visitMethodInsn(INVOKESTATIC,
clazz,
@ -125,7 +125,7 @@ public class JInvokeStatic extends FactorWordDefinition
if(returnType != Void.TYPE)
{
FactorJava.generateToConversion(mw,returnType);
allocator.push(mw);
compiler.push(mw);
}
return 4 + args.length;

View File

@ -32,7 +32,7 @@ package factor.primitives;
import factor.compiler.*;
import factor.*;
import java.lang.reflect.*;
import java.util.Set;
import java.util.Map;
import org.objectweb.asm.*;
public class JNew extends FactorWordDefinition
@ -59,8 +59,8 @@ public class JNew extends FactorWordDefinition
/**
* XXX: does not use factor type system conversions.
*/
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws Exception
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler state) throws Exception
{
state.ensure(state.datastack,2);
@ -74,28 +74,27 @@ public class JNew extends FactorWordDefinition
(String)clazz,
(Cons)args);
int params = constructor.getParameterTypes().length;
state.consume(state.datastack,params);
state.push(null);
return new StackEffect(
2 + constructor.getParameterTypes()
.length,1,0,0);
}
else
return null;
throw new FactorCompilerException("Cannot deduce stack effect of " + word + " with non-literal arguments");;
} //}}}
//{{{ compileCallTo() method
//{{{ compileImmediate() method
/**
* Compile a call to this word. Returns maximum JVM stack use.
* XXX: does not use factor type system conversions.
*/
public int compileCallTo(
public int compileImmediate(
CodeVisitor mw,
LocalAllocator allocator,
Set recursiveCheck)
FactorCompiler compiler,
RecursiveState recursiveCheck)
throws Exception
{
Object _clazz = allocator.popLiteral();
Object _args = allocator.popLiteral();
Object _clazz = compiler.popLiteral();
Object _args = compiler.popLiteral();
if(_clazz instanceof String &&
(_args == null || _args instanceof Cons))
{
@ -107,7 +106,7 @@ public class JNew extends FactorWordDefinition
mw.visitTypeInsn(NEW,clazz);
mw.visitInsn(DUP);
allocator.generateArgs(mw,args.length,args);
compiler.generateArgs(mw,args.length,args);
mw.visitMethodInsn(INVOKESPECIAL,
clazz,
@ -115,7 +114,7 @@ public class JNew extends FactorWordDefinition
FactorJava.javaSignatureToVMSignature(
args,void.class));
allocator.push(mw);
compiler.push(mw);
return 3 + args.length;
}

View File

@ -32,7 +32,7 @@ package factor.primitives;
import factor.compiler.*;
import factor.*;
import java.lang.reflect.*;
import java.util.Set;
import java.util.Map;
import org.objectweb.asm.*;
public class JVarGet extends FactorWordDefinition
@ -57,15 +57,14 @@ public class JVarGet extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws FactorStackException
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler 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
@ -75,12 +74,12 @@ public class JVarGet extends FactorWordDefinition
*/
public int compileCallTo(
CodeVisitor mw,
LocalAllocator allocator,
Set recursiveCheck)
FactorCompiler compiler,
RecursiveState recursiveCheck)
throws Exception
{
Object _field = allocator.popLiteral();
Object _clazz = allocator.popLiteral();
Object _field = compiler.popLiteral();
Object _clazz = compiler.popLiteral();
if(_clazz instanceof String &&
_field instanceof String)
{
@ -92,7 +91,7 @@ public class JVarGet extends FactorWordDefinition
FactorJava.generateToConversionPre(mw,fld.getType());
allocator.pop(mw);
compiler.pop(mw);
FactorJava.generateFromConversion(mw,cls);
mw.visitFieldInsn(GETFIELD,clazz,field,
@ -100,7 +99,7 @@ public class JVarGet extends FactorWordDefinition
FactorJava.generateToConversion(mw,fld.getType());
allocator.push(mw);
compiler.push(mw);
return 2;
}

View File

@ -32,7 +32,7 @@ package factor.primitives;
import factor.compiler.*;
import factor.*;
import java.lang.reflect.*;
import java.util.Set;
import java.util.Map;
import org.objectweb.asm.*;
public class JVarGetStatic extends FactorWordDefinition
@ -56,14 +56,13 @@ public class JVarGetStatic extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws FactorStackException
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler 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
@ -73,12 +72,12 @@ public class JVarGetStatic extends FactorWordDefinition
*/
public int compileCallTo(
CodeVisitor mw,
LocalAllocator allocator,
Set recursiveCheck)
FactorCompiler compiler,
RecursiveState recursiveCheck)
throws Exception
{
Object _field = allocator.popLiteral();
Object _clazz = allocator.popLiteral();
Object _field = compiler.popLiteral();
Object _clazz = compiler.popLiteral();
if(_clazz instanceof String &&
_field instanceof String)
{
@ -95,7 +94,7 @@ public class JVarGetStatic extends FactorWordDefinition
FactorJava.generateToConversion(mw,fld.getType());
allocator.push(mw);
compiler.push(mw);
return 2;
}

View File

@ -32,7 +32,7 @@ package factor.primitives;
import factor.compiler.*;
import factor.*;
import java.lang.reflect.*;
import java.util.Set;
import java.util.Map;
import org.objectweb.asm.*;
public class JVarSet extends FactorWordDefinition
@ -58,15 +58,14 @@ public class JVarSet extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws FactorStackException
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler 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
@ -76,12 +75,12 @@ public class JVarSet extends FactorWordDefinition
*/
public int compileCallTo(
CodeVisitor mw,
LocalAllocator allocator,
Set recursiveCheck)
FactorCompiler compiler,
RecursiveState recursiveCheck)
throws Exception
{
Object _field = allocator.popLiteral();
Object _clazz = allocator.popLiteral();
Object _field = compiler.popLiteral();
Object _clazz = compiler.popLiteral();
if(_clazz instanceof String &&
_field instanceof String)
{
@ -91,10 +90,10 @@ public class JVarSet extends FactorWordDefinition
clazz = clazz.replace('.','/');
Field fld = cls.getField(field);
allocator.pop(mw);
compiler.pop(mw);
FactorJava.generateFromConversion(mw,cls);
allocator.pop(mw);
compiler.pop(mw);
FactorJava.generateFromConversion(mw,fld.getType());
mw.visitFieldInsn(PUTFIELD,

View File

@ -32,7 +32,7 @@ package factor.primitives;
import factor.compiler.*;
import factor.*;
import java.lang.reflect.*;
import java.util.Set;
import java.util.Map;
import org.objectweb.asm.*;
public class JVarSetStatic extends FactorWordDefinition
@ -56,14 +56,13 @@ public class JVarSetStatic extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(Set recursiveCheck,
LocalAllocator state) throws FactorStackException
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler 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
@ -73,12 +72,12 @@ public class JVarSetStatic extends FactorWordDefinition
*/
public int compileCallTo(
CodeVisitor mw,
LocalAllocator allocator,
Set recursiveCheck)
FactorCompiler compiler,
RecursiveState recursiveCheck)
throws Exception
{
Object _field = allocator.popLiteral();
Object _clazz = allocator.popLiteral();
Object _field = compiler.popLiteral();
Object _clazz = compiler.popLiteral();
if(_clazz instanceof String &&
_field instanceof String)
{
@ -88,7 +87,7 @@ public class JVarSetStatic extends FactorWordDefinition
clazz = clazz.replace('.','/');
Field fld = cls.getField(field);
allocator.pop(mw);
compiler.pop(mw);
FactorJava.generateFromConversion(mw,fld.getType());
mw.visitFieldInsn(PUTSTATIC,

View File

@ -31,6 +31,7 @@ package factor.primitives;
import factor.compiler.*;
import factor.*;
import java.util.Map;
public class Set extends FactorWordDefinition
{
@ -59,12 +60,11 @@ public class Set extends FactorWordDefinition
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect(java.util.Set recursiveCheck,
LocalAllocator state) throws FactorStackException
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler state) throws FactorStackException
{
state.ensure(state.datastack,2);
state.pop(null);
state.pop(null);
return new StackEffect(2,0,0,0);
} //}}}
}

View File

@ -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.
"user.home" system-property @~
"file.separator" system-property @/
: <stream> ( -- stream )
! Create a stream object. A stream is a namespace with the
! following entries:
@ -42,6 +45,8 @@
[ "freadln not implemented." break ] @freadln
( string -- )
[ "fwrite not implemented." break ] @fwrite
( string -- )
[ "fedit not implemented." break ] @fedit
( -- )
[ ] @fflush
( -- )
@ -165,6 +170,12 @@
: fwrite ( string stream -- )
[ $fwrite call ] bind ;
: fedit ( string stream -- )
[ $fedit call ] bind ;
: edit ( string -- )
$stdio fedit ;
: fclose ( stream -- )
[ $fclose call ] bind ;
@ -175,14 +186,8 @@
[ "java.io.InputStream" "java.io.OutputStream" ]
"factor.FactorLib" "copy" jinvoke-static ;
"java.lang.System" "in" jvar-static$ <ireader> <breader> @stdin
"java.lang.System" "out" jvar-static$ <owriter> @stdout
$stdin $stdout <charstream> @stdio
!(file -- freader)
|<freader> [
[ |java.lang.String ] |java.io.FileReader jnew <breader>
] define
: <freader> ( file -- freader )
[ |java.lang.String ] |java.io.FileReader jnew <breader> ;
: <file> (path -- file)
dup "java.io.File" is not [
@ -206,10 +211,8 @@ $stdin $stdout <charstream> @stdio
[ "java.io.File" ] "java.io.File" "renameTo"
jinvoke ;
!(string -- reader)
|<sreader> [
[ |java.lang.String ] |java.io.StringReader jnew
] define
: <sreader> (string -- reader)
[ |java.lang.String ] |java.io.StringReader jnew ;
: close (stream --)
dup "java.io.Reader" is [
@ -222,18 +225,18 @@ $stdin $stdout <charstream> @stdio
[ [ "java.lang.String" ] ] "factor.FactorLib" "exec"
jinvoke-static ;
!(stream -- string)
|read* [
[ ] |java.io.BufferedReader |readLine jinvoke
] define
: print-numbered-list* ( number list -- )
! Print each element of the list with a number.
dup [
uncons [ over pred ] dip print-numbered-list*
": " swap cat3 print
] [
2drop
] ifte ;
: print* (string stream --)
tuck write*
"\n" swap write* ;
: print-numbered-list ( list -- )
dup length pred swap print-numbered-list* ;
!(string stream --)
|write* [
tuck
[ |java.lang.String ] |java.io.Writer |write jinvoke
[ ] |java.io.Writer |flush jinvoke
] define
"java.lang.System" "in" jvar-static$ <ireader> <breader> @stdin
"java.lang.System" "out" jvar-static$ <owriter> @stdout
$stdin $stdout <charstream> @stdio

View File

@ -35,10 +35,6 @@
! [ #\" , "&quot;" ]
] @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.
@ -46,6 +42,19 @@
[ "java.lang.String" ] "java.lang.String" "getBytes"
jinvoke ;
: >lower ( str -- str )
[ ] "java.lang.String" "toLowerCase" jinvoke ;
: >str ( obj -- string )
! Returns the Java string representation of this object.
[ ] "java.lang.Object" "toString" jinvoke ;
: >title ( str -- str )
1 str/ [ >upper ] dip >lower cat2 ;
: >upper ( str -- str )
[ ] "java.lang.String" "toUpperCase" jinvoke ;
: <sbuf> ( -- StringBuffer )
[ ] "java.lang.StringBuffer" jnew ;
@ -67,12 +76,15 @@
: cat4 ( "a" "b" "c" "d" -- "abcd" )
[ ] cons cons cons cons cat ;
: cat5 ( "a" "b" "c" "d" "e" -- "abcde" )
[ ] cons 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 rot ? ] str-map ;
: group ( index match -- )
[ "int" ] "java.util.regex.Matcher" "group"
@ -151,6 +163,10 @@
jinvoke-static
] when ;
: spaces ( len -- str )
! Returns a string containing the given number of spaces.
<sbuf> swap [ " " swap sbuf-append ] times >str ;
: split ( string split -- list )
2dup index-of dup -1 = [
2drop unit
@ -158,16 +174,27 @@
swap [ str// ] dip split cons
] ifte ;
: string? ( obj -- ? )
"java.lang.String" is ;
: str->=< ( str1 str2 -- n )
swap [ "java.lang.String" ] "java.lang.String" "compareTo"
jinvoke ;
: str-lexi> ( str1 str2 -- ? )
! Returns if the first string lexicographically follows str2
str->=< 0 > ;
: str/ ( str index -- str str )
! Returns 2 strings, that when concatenated yield the
! original string.
2dup strtail [ str-head ] dip ;
2dup str-tail [ str-head ] dip ;
: 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 ;
2dup succ str-tail [ str-head ] dip ;
: str-each ( str [ code ] -- )
! Execute the code, with each character of the string pushed
@ -205,12 +232,15 @@
: str-length> ( str str -- boolean )
! Compare string lengths.
[ str-length ] apply2 > ;
[ str-length ] 2apply > ;
: str-map ( str [ code ] -- [ mapping ] )
2list restack str-each unstack cat ;
: strtail ( str index -- str )
: str-contains ( substr str -- ? )
swap index-of -1 = not ;
: str-tail ( str index -- str )
! Returns a new string, from the given index until the end
! of the string.
over str-length rot substring ;

View File

@ -0,0 +1,6 @@
! Tests the combinators.
"Checking combinators." print
[ ] [ 3 ] [ [ ] cond ] test-word
[ t ] [ 4 ] [ [ [ 1 = ] [ ] [ 4 = ] [ drop t ] [ 2 = ] [ ] ] cond ] test-word

View File

@ -0,0 +1,55 @@
! Compiler tests
"Checking compiler." print
[ 1 2 3 ] [ 4 5 6 ] [ t [ drop drop drop 1 2 3 ] when ] test-word
[ 4 5 6 ] [ 4 5 6 ] [ f [ drop drop drop 1 2 3 ] when ] test-word
[ t ] [ t ] [ [ t ] [ f ] rot [ drop call ] [ nip call ] ifte ] test-word
[ f ] [ f ] [ [ t ] [ f ] rot [ drop call ] [ nip call ] ifte ] test-word
[ 4 ] [ 2 ] [ t [ 2 ] [ 3 ] ifte + ] test-word
[ 5 ] [ 2 ] [ f [ 2 ] [ 3 ] ifte + ] test-word
: stack-frame-test ( x -- x )
>r t [ r> ] [ rdrop 11 ] ifte ;
[ 10 ] [ 10 ] [ stack-frame-test ] test-word
: balance>list ( quotation -- list )
balance effect>list ;
[ [ 1 1 0 0 ] ] [ [ sq ] ] [ balance>list ] test-word
[ [ 2 1 0 0 ] ] [ [ mag2 ] ] [ balance>list ] test-word
[ [ 2 1 0 0 ] ] [ [ append ] ] [ balance>list ] test-word
[ [ 1 1 0 0 ] ] [ [ fac ] ] [ balance>list ] test-word
[ [ 1 1 0 0 ] ] [ [ fib ] ] [ balance>list ] test-word
[ [ 1 1 0 0 ] ] [ [ dup [ sq ] when ] ] [ balance>list ] test-word
: test-null-rec ( -- )
[ [ 0 0 0 0 ] ] [ [ null-rec ] ] [ balance>list ] test-word ;
: null-rec ( -- )
t [ null-rec ] when ; compile-maybe test-null-rec
: null-rec ( -- )
t [ null-rec ] unless ; compile-maybe test-null-rec
: null-rec ( -- )
t [ drop null-rec ] when* ; compile-maybe test-null-rec
!: null-rec ( -- )
! t [ t null-rec ] unless* drop ; compile-maybe test-null-rec
[ f 1 2 3 ] [ [ [ 2 , 1 ] ] 3 ] [ [ unswons unswons ] dip ] test-word
[ [ 2 1 0 0 ] ] [ [ >r [ ] [ ] ? call r> ] ] [ balance>list ] test-word
: nested-rec ( -- )
t [ nested-rec ] when ; compile-maybe
: nested-rec-test ( -- )
5 nested-rec drop ; compile-maybe
[ [ 0 0 0 0 ] ] [ [ nested-rec-test ] ] [ balance>list ] test-word
"All compiler checks passed." print

View File

@ -0,0 +1,37 @@
! Tests the dictionary words.
"Checking dictionary words." print
! Just make sure this works.
! OUTPUT INPUT WORD
[ ] [ "httpd" ] [ apropos ] test-word
[ t ] [ "ifte" ] [ worddef compound? ] test-word
[ t ] [ "dup" ] [ worddef shuffle? ] test-word
[ f ] [ "ifte" ] [ worddef shuffle? ] test-word
[ f ] [ "dup" ] [ worddef compound? ] test-word
! Test word iternalization.
: gensym-test ( -- ? )
f 10 [ gensym gensym = and ] times ;
[ f ] [ ] [ gensym-test ] test-word
: intern-test ( 1 2 -- ? )
[ intern ] 2apply = ;
[ t ] [ "a" "a" ] [ intern-test ] test-word
[ f ] [ "a" "A" ] [ intern-test ] test-word
[ f ] [ "a" "B" ] [ intern-test ] test-word
[ f ] [ "a" "a" ] [ <word> swap intern = ] test-word
: worddef>list-test ( -- ? )
[ dup * ] dup no-name worddef>list cdr cdr = ;
[ t ] [ ] [ worddef>list-test ] test-word
: words-test ( -- ? )
t words [ word? and ] each ;
[ t ] [ ] [ words-test ] test-word

153
factor/test/list.factor Normal file
View File

@ -0,0 +1,153 @@
! Tests the list words.
"Checking list words." print
! OUTPUT INPUT WORD
[ [ 1 2 ] ] [ 1 2 ] [ 2list ] test-word
[ [ 1 2 3 ] ] [ 1 2 3 ] [ 3list ] test-word
[ [ 2 1 ] ] [ 1 2 ] [ 2rlist ] test-word
[ [ ] ] [ [ ] [ ] ] [ append ] test-word
[ [ 1 ] ] [ [ 1 ] [ ] ] [ append ] test-word
[ [ 2 ] ] [ [ ] [ 2 ] ] [ append ] test-word
[ [ 1 2 3 4 ] ] [ [ 1 2 3 ] [ 4 ] ] [ append ] test-word
[ [ 1 2 3 4 ] ] [ [ 3 4 ] [ 1 2 ] ] [ @x "x" append@ $x ] test-word
[ [ ] ] [ [ ] ] [ array>list ] test-word
[ [ 1 2 3 ] ] [ [ 1 2 3 ] ] [ array>list ] test-word
[ [ 1 2 3 4 ] ] [ 4 [ 1 2 3 ] ] [ @x "x" add@ $x ] test-word
[
[ "monkey" , 1 ]
[ "banana" , 2 ]
[ "Java" , 3 ]
[ t , "true" ]
[ f , "false" ]
[ [ 1 2 ] , [ 2 1 ] ]
] @assoc
[ f ] [ "monkey" f ] [ assoc ] test-word
[ f ] [ "donkey" $assoc ] [ assoc ] test-word
[ 1 ] [ "monkey" $assoc ] [ assoc ] test-word
[ "false" ] [ f $assoc ] [ assoc ] test-word
[ [ 2 1 ] ] [ [ 1 2 ] $assoc ] [ assoc ] test-word
f @monkey
t @donkey
[ 1 2 ] @lisp
[
[ "monkey" , 1 ]
[ "donkey" , 2 ]
[ "lisp" , [ 2 1 ] ]
] @assoc
[ 1 ] [ f $assoc ] [ assoc$ ] test-word
[ [ 2 1 ] ] [ [ 1 2 ] $assoc ] [ assoc$ ] test-word
[ 1 ] [ [ 1 , 2 ] ] [ car ] test-word
[ 2 ] [ [ 1 , 2 ] ] [ cdr ] test-word
[ [ ] ] [ [ ] ] [ clone-list ] test-word
[ [ 1 2 , 3 ] ] [ [ 1 2 , 3 ] ] [ clone-list ] test-word
[ [ 1 2 3 4 ] ] [ [ 1 2 3 4 ] ] [ clone-list ] test-word
: clone-list-actually-clones? ( list1 list2 -- )
[ clone-list ] dip ! we don't want to mutate literals
[ dup clone-list ] dip nappend = not ;
[ t ] [ [ 1 2 ] [ 3 4 ] ] [ clone-list-actually-clones? ] test-word
[ [ 1 , 2 ] ] [ 1 2 ] [ cons ] test-word
[ [ 1 ] ] [ 1 f ] [ cons ] test-word
[ f ] [ 3 [ ] ] [ contains ] test-word
[ f ] [ 3 [ 1 2 ] ] [ contains ] test-word
[ [ 1 2 ] ] [ 1 [ 1 2 ] ] [ contains ] test-word
[ [ 2 ] ] [ 2 [ 1 2 ] ] [ contains ] test-word
[ [ 1 ] ] [ 1 f ] [ @x "x" cons@ $x ] test-word
[ [ 1 , 2 ] ] [ 1 2 ] [ @x "x" cons@ $x ] test-word
[ [ 1 2 ] ] [ 1 [ 2 ] ] [ @x "x" cons@ $x ] test-word
[ [ ] ] [ 0 ] [ count ] test-word
[ [ ] ] [ -10 ] [ count ] test-word
[ [ ] ] [ $-inf ] [ count ] test-word
[ [ 0 1 2 ] ] [ $e ] [ count ] test-word
[ [ 0 1 2 3 ] ] [ 4 ] [ count ] test-word
[ 1 ] [ [ 1 2 ] -1 ] [ get ] test-word
[ 1 ] [ [ 1 2 ] 0 ] [ get ] test-word
[ 2 ] [ [ 1 2 ] 1 ] [ get ] test-word
[ [ 3 ] ] [ [ 3 ] ] [ last* ] test-word
[ [ 3 ] ] [ [ 1 2 3 ] ] [ last* ] test-word
[ [ 3 , 4 ] ] [ [ 1 2 3 , 4 ] ] [ last* ] test-word
[ 3 ] [ [ 3 ] ] [ last ] test-word
[ 3 ] [ [ 1 2 3 ] ] [ last ] test-word
[ 3 ] [ [ 1 2 3 , 4 ] ] [ last ] test-word
[ 0 ] [ [ ] ] [ length ] test-word
[ 3 ] [ [ 1 2 3 ] ] [ length ] test-word
! CMU CL bombs on (length '(1 2 3 . 4))
![ 3 ] [ [ 1 2 3 , 4 ] ] [ length ] test-word
[ t ] [ f ] [ list? ] test-word
[ f ] [ t ] [ list? ] test-word
[ t ] [ [ 1 2 ] ] [ list? ] test-word
[ f ] [ [ 1 , 2 ] ] [ list? ] test-word
: clone-and-nappend ( list list -- list )
[ clone-list ] 2apply nappend ;
[ [ ] ] [ [ ] [ ] ] [ clone-and-nappend ] test-word
[ [ 1 ] ] [ [ 1 ] [ ] ] [ clone-and-nappend ] test-word
[ [ 2 ] ] [ [ ] [ 2 ] ] [ clone-and-nappend ] test-word
[ [ 1 2 3 4 ] ] [ [ 1 2 3 ] [ 4 ] ] [ clone-and-nappend ] test-word
[ 1 2 3 ] clone-list @x [ 4 5 6 ] clone-list @y
[ [ 4 5 6 ] ] [ $x $y ] [ nappend drop $y ] test-word
[ 1 2 3 ] clone-list @x [ 4 5 6 ] clone-list @y
[ [ 1 2 3 4 5 6 ] ] [ $x $y ] [ nappend drop $x ] test-word
[ f ] [ f ] [ cons? ] test-word
[ f ] [ t ] [ cons? ] test-word
[ t ] [ [ t , f ] ] [ cons? ] test-word
[ [ ] ] [ [ ] ] [ reverse ] test-word
[ [ 1 ] ] [ [ 1 ] ] [ reverse ] test-word
[ [ 3 2 1 ] ] [ [ 1 2 3 ] ] [ reverse ] test-word
[ a , b ] clone-list @x
[ [ 1 , b ] ] [ 1 $x ] [ rplaca $x ] test-word
[ a , b ] clone-list @x
[ [ a , 2 ] ] [ 2 $x ] [ rplacd $x ] test-word
[ [ 1 , 2 ] ] [ 2 1 ] [ swons ] test-word
[ [ 1 ] ] [ f 1 ] [ swons ] test-word
[ [ 1 ] ] [ 1 f ] [ @x "x" swap swons@ $x ] test-word
[ [ 1 , 2 ] ] [ 1 2 ] [ @x "x" swap swons@ $x ] test-word
[ [ 1 2 ] ] [ 1 [ 2 ] ] [ @x "x" swap swons@ $x ] test-word
[ 1 2 ] [ [ 1 , 2 ] ] [ uncons ] test-word
[ 1 [ 2 ] ] [ [ 1 2 ] ] [ uncons ] test-word
[ [ 1 2 3 ] ] [ 1 [ 2 3 ] ] [ unique ] test-word
[ [ 1 2 3 ] ] [ 1 [ 1 2 3 ] ] [ unique ] test-word
[ [ 1 2 3 ] ] [ 2 [ 1 2 3 ] ] [ unique ] test-word
[ [ [ [ ] ] ] ] [ [ ] ] [ unit unit ] test-word
[ 1 2 ] [ [ 2 , 1 ] ] [ unswons ] test-word
[ [ 2 ] 1 ] [ [ 1 2 ] ] [ unswons ] test-word
"List checks passed." print

View File

@ -0,0 +1,22 @@
! Miscellaneous tests.
"Miscellaneous tests." print
: test-last ( -- )
nop ;
word >str @last-word-test
[ "test-last" ] [ ] [ $last-word-test ] test-word
[ f ] [ 5 ] [ compound? ] test-word
[ f ] [ 5 ] [ compiled? ] test-word
[ f ] [ 5 ] [ shuffle? ] test-word
! These stress-test a lot of code.
"prettyprint*" see
"prettyprint*" see/html
$global describe
$global describe/html
[ t ] [ ] [ [ "global" "stdio" ] object-path $stdio = ] test-word
"Miscellaneous passed." print

13
factor/test/random.factor Normal file
View File

@ -0,0 +1,13 @@
! Random tests
"Checking random number generation." print
[
[ 10 , t ]
[ 20 , f ]
[ 30 , "monkey" ]
] @random-pairs
[ f ] [ $random-pairs ] [ random-element* [ t f "monkey" ] contains not ] test-word
"Random number checks complete." print

36
factor/test/stack.factor Normal file
View File

@ -0,0 +1,36 @@
! Test the built-in stack words.
"Checking stack words." print
! OUTPUT INPUT WORD
[ ] [ 1 ] [ drop ] test-word
[ ] [ 1 2 ] [ 2drop ] test-word
[ 1 1 ] [ 1 ] [ dup ] test-word
[ 1 2 1 2 ] [ 1 2 ] [ 2dup ] test-word
[ 1 1 2 ] [ 1 2 ] [ dupd ] test-word
[ 1 2 1 2 3 4 ] [ 1 2 3 4 ] [ 2dupd ] test-word
[ 2 ] [ 1 2 ] [ nip ] test-word
[ 3 4 ] [ 1 2 3 4 ] [ 2nip ] test-word
[ ] [ ] [ nop ] test-word
[ 1 2 1 ] [ 1 2 ] [ over ] test-word
[ 1 2 3 4 1 2 ] [ 1 2 3 4 ] [ 2over ] test-word
[ 1 2 3 1 ] [ 1 2 3 ] [ pick ] test-word
[ 2 3 1 ] [ 1 2 3 ] [ rot ] test-word
[ 3 4 5 6 1 2 ] [ 1 2 3 4 5 6 ] [ 2rot ] test-word
[ 3 1 2 ] [ 1 2 3 ] [ -rot ] test-word
[ 5 6 1 2 3 4 ] [ 1 2 3 4 5 6 ] [ 2-rot ] test-word
[ 2 1 ] [ 1 2 ] [ swap ] test-word
[ 3 4 1 2 ] [ 1 2 3 4 ] [ 2swap ] test-word
[ 2 1 3 ] [ 1 2 3 ] [ swapd ] test-word
[ 3 4 1 2 5 6 ] [ 1 2 3 4 5 6 ] [ 2swapd ] test-word
[ 3 2 1 ] [ 1 2 3 ] [ transp ] test-word
[ 5 6 3 4 1 2 ] [ 1 2 3 4 5 6 ] [ 2transp ] test-word
[ 2 1 2 ] [ 1 2 ] [ tuck ] test-word
[ 3 4 1 2 3 4 ] [ 1 2 3 4 ] [ 2tuck ] test-word
[ ] [ 1 ] [ >r rdrop ] test-word
[ 2 1 2 ] [ 1 2 ] [ >r >r rover r> r> r> ] test-word
[ 2 1 ] [ 1 2 ] [ 2>r r> r> ] test-word
[ 2 1 ] [ 1 2 ] [ >r >r 2r> ] test-word
"Stack checks passed." print

40
factor/test/test.factor Normal file
View File

@ -0,0 +1,40 @@
! Factor test suite.
! Some of these words should be moved to the standard library.
: assert ( t -- )
[ "Assertion failed!" break ] unless ;
: assert= ( x y -- )
= assert ;
: compile-maybe ( -- )
$compile [ word compile ] when ;
: compile-no-name ( list -- )
no-name compile-maybe ;
~<< 3dup A B C -- A B C A B C >>~
: test-word ( output word input )
3dup 3list .
append compile-no-name unit expand assert= ;
: test ( name -- )
! Run the given test.
"/factor/test/" swap ".factor" cat3 runResource ;
: all-tests ( -- )
"Running Factor test suite..." print
[
"combinators"
"compiler"
"dictionary"
"list"
"miscellaneous"
"random"
"stack"
] [
test
] each
"All tests passed." print ;

View File

@ -1 +1 @@
"0.36" @version
"0.53" @version