communicates stack effect from socket

cvs
Slava Pestov 2004-11-19 22:28:23 +00:00
parent 84d1667fdf
commit cf75abc247
19 changed files with 89 additions and 1740 deletions

View File

@ -135,7 +135,11 @@ public class ExternalFactor extends DefaultVocabularyLookup
return null;
result = (Cons)result.car;
return new FactorWord((String)result.car,(String)result.next().car);
w = new FactorWord(
(String)result.car,
(String)result.next().car);
w.stackEffect = (String)result.next().next().car;
return w;
}
catch(Exception e)
{

View File

@ -38,7 +38,6 @@ import java.util.*;
public class FactorCompoundDefinition extends FactorWordDefinition
{
public Cons definition;
private Cons endOfDocs;
//{{{ FactorCompoundDefinition constructor
/**
@ -48,15 +47,6 @@ public class FactorCompoundDefinition extends FactorWordDefinition
{
super(word);
this.definition = definition;
if(definition == null)
endOfDocs = null;
else
{
endOfDocs = definition;
while(endOfDocs != null
&& endOfDocs.car instanceof FactorDocComment)
endOfDocs = endOfDocs.next();
}
} //}}}
//{{{ toList() method

View File

@ -1,59 +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;
import java.io.IOException;
public class FactorDocComment implements FactorExternalizable
{
private String msg;
private boolean stack;
public FactorDocComment(String msg, boolean stack)
{
if(stack)
msg = msg.trim();
this.msg = msg;
this.stack = stack;
}
public String toString()
{
if(stack)
return "( " + msg + " )\n";
else
return "#! " + msg + "\n";
}
public boolean isStackComment()
{
return stack;
}
}

View File

@ -1,52 +0,0 @@
/* :folding=explicit:collapseFolds=1: */
/*
* $Id$
*
* Copyright (C) 2003, 2004 Slava Pestov.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package factor;
import java.util.Set;
/**
* All primitive words extend this.
*/
public abstract class FactorPrimitiveDefinition extends FactorWordDefinition
{
//{{{ FactorPrimitiveDefinition constructor
/**
* A new definition.
*/
public FactorPrimitiveDefinition(FactorWord word)
{
super(word);
} //}}}
//{{{ fromList() method
public void fromList(Cons cons)
{
} //}}}
}

View File

@ -269,6 +269,8 @@ public class FactorReader
w.line = line;
w.col = col;
w.file = scanner.getFileName();
w.stackEffect = null;
w.documentation = null;
}
return w;
}
@ -313,8 +315,7 @@ public class FactorReader
return true;
else if(next instanceof String)
{
FactorWord word = intern((String)next,
!getCurrentState().warnUndefined);
FactorWord word = intern((String)next,false);
if(word == null)
{
/* We're ignoring errors */
@ -341,24 +342,22 @@ public class FactorReader
* An exclusive state can only happen at the top level.
* For example, : ... ; definitions cannot be nested so they
* are exclusive.
*
* @param args Parsing words can use this to store arbitrary info
*/
public void pushExclusiveState(FactorWord start, Object args)
public void pushExclusiveState(FactorWord start, FactorWord defining)
throws FactorParseException
{
if(getCurrentState().start != toplevel)
scanner.error(start + " cannot be nested");
pushState(start,args);
pushState(start,defining);
} //}}}
//{{{ pushState() method
/**
* Push a parser state, for example reading of a list.
*/
public void pushState(FactorWord start, Object args)
public void pushState(FactorWord start, FactorWord defining)
{
states = new Cons(new ParseState(start,args),states);
states = new Cons(new ParseState(start,defining),states);
} //}}}
//{{{ popState() method
@ -391,6 +390,18 @@ public class FactorReader
getCurrentState().append(obj);
} //}}}
//{{{ setStackComment() method
public void setStackComment(String comment)
{
getCurrentState().setStackComment(comment);
} //}}}
//{{{ addDocComment() method
public void addDocComment(String comment)
{
getCurrentState().addDocComment(comment);
} //}}}
//{{{ bar() method
/**
* Sets the current parser state's cdr to the given object.
@ -410,39 +421,24 @@ public class FactorReader
public class ParseState
{
public FactorWord start;
public Object arg;
public FactorWord defining;
public Cons first;
public Cons last;
public boolean warnUndefined;
private boolean comma;
private boolean bar;
private boolean docComment;
ParseState(FactorWord start, Object arg)
ParseState(FactorWord start, FactorWord defining)
{
docComment = start.docComment;
warnUndefined = true;
this.start = start;
this.arg = arg;
this.defining = defining;
}
void append(Object obj) throws FactorParseException
{
boolean docComment = (this.docComment || alwaysDocComments);
// In a doc comment context, first object is always
// a word, then followed by doc comments, then followed
// by code.
if(docComment && !(obj instanceof FactorDocComment)
&& first != null)
{
this.docComment = false;
}
else if(!docComment && obj instanceof FactorDocComment)
{
//scanner.error("Documentation comment not allowed here");
return;
}
docComment = false;
if(comma)
if(bar)
{
if(last.cdr != null)
scanner.error("Only one token allowed after |");
@ -459,6 +455,27 @@ public class FactorReader
}
}
void setStackComment(String comment)
{
if(defining != null && defining.stackEffect == null)
defining.stackEffect = comment;
}
void addDocComment(String comment)
{
if(defining != null && (docComment || alwaysDocComments))
{
if(defining.documentation == null)
defining.documentation = comment;
else
{
/* Its O(n^2). Big deal. */
defining.documentation = defining.documentation
.concat(comment);
}
}
}
void bar() throws FactorParseException
{
if(last.cdr != null)
@ -468,7 +485,7 @@ public class FactorReader
scanner.error("Only one token allowed after |");
}
comma = true;
bar = true;
}
} //}}}
}

View File

@ -1,43 +0,0 @@
/* :folding=explicit:collapseFolds=1: */
/*
* $Id$
*
* Copyright (C) 2003 Slava Pestov.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package factor;
public class FactorRuntimeException extends FactorException
{
public FactorRuntimeException(String str)
{
super(str);
}
public FactorRuntimeException(String str, Throwable t)
{
super(str,t);
}
}

View File

@ -36,21 +36,21 @@ import java.util.*;
*/
public class FactorWord implements FactorExternalizable
{
private static int gensymCount = 0;
public String vocabulary;
public String name;
/**
* Interpreted/compiled word definition.
*/
public FactorWordDefinition def;
public String stackEffect;
public String documentation;
/**
* Parsing word definition.
*/
public FactorParsingDefinition parsing;
/**
* Stub for interpreter definitin.
*/
public FactorWordDefinition def;
/**
* Should the parser keep doc comments?
*/
@ -64,37 +64,12 @@ public class FactorWord implements FactorExternalizable
public int col;
//{{{ FactorWord constructor
/**
* Do not use this constructor unless you're writing a packages
* implementation or something. Use an FactorDictionary's
* intern() method instead.
*/
public FactorWord(String vocabulary, String name,
FactorWordDefinition def)
{
this.vocabulary = vocabulary;
this.name = name;
this.def = def;
} //}}}
//{{{ FactorWord constructor
/**
* Do not use this constructor unless you're writing a packages
* implementation or something. Use an FactorDictionary's
* intern() method instead.
*/
public FactorWord(String vocabulary, String name)
{
this.vocabulary = vocabulary;
this.name = name;
} //}}}
//{{{ define() method
public void define(FactorWordDefinition def)
{
this.def = def;
} //}}}
//{{{ toString() method
public String toString()
{

View File

@ -1,444 +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.db.*;
import factor.compiler.*;
import java.io.*;
import java.util.*;
import org.objectweb.asm.*;
/**
* A word definition.
*
* The pickled form is an unparsed list. The car of the list is the word,
* the cdr is toList().
*/
public abstract class FactorWordDefinition
implements Constants, PersistentObject
{
public static final String ENCODING = "UTF8";
private Workspace workspace;
private long id;
public FactorWord word;
public boolean compileFailed;
//{{{ FactorWordDefinition constructor
/**
* A new definition.
*/
public FactorWordDefinition(FactorWord word, Workspace workspace)
{
this(workspace,workspace == null
? 0L : workspace.nextID());
this.word = word;
} //}}}
//{{{ FactorWordDefinition constructor
/**
* A blank definition, about to be unpickled.
*/
public FactorWordDefinition(Workspace workspace, long id)
{
this.workspace = workspace;
this.id = id;
} //}}}
//{{{ FactorWordDefinition constructor
/**
* A definition that is not saved in the current workspace.
*/
public FactorWordDefinition(FactorWord word)
{
this.word = word;
} //}}}
public abstract void eval(FactorInterpreter interp)
throws Exception;
//{{{ fromList() method
public void fromList(Cons cons, FactorInterpreter interp)
throws FactorRuntimeException, PersistenceException
{
throw new PersistenceException("Cannot unpickle " + this);
} //}}}
//{{{ toList() method
public Cons toList(FactorInterpreter interp)
{
return new Cons(new FactorWord(null,getClass().getName()),null);
} //}}}
//{{{ getStackEffect() method
public final StackEffect getStackEffect(FactorInterpreter interp)
throws Exception
{
return getStackEffect(interp,new RecursiveState());
} //}}}
//{{{ getStackEffect() method
public final StackEffect getStackEffect(FactorInterpreter interp,
RecursiveState recursiveCheck)
throws Exception
{
FactorCompiler compiler = new FactorCompiler(interp);
recursiveCheck.add(word,new StackEffect(),null,null,null);
compileCallTo(null,compiler,recursiveCheck);
recursiveCheck.remove(word);
return compiler.getStackEffect();
} //}}}
/*
//{{{ getStackEffect() method
public void getStackEffect(RecursiveState recursiveCheck,
FactorCompiler compiler) throws Exception
{
compileCallTo(null,compiler,recursiveCheck);
} //}}}
*/
//{{{ compile() method
FactorWordDefinition compile(FactorInterpreter interp,
RecursiveState recursiveCheck) throws Exception
{
return this;
} //}}}
//{{{ getDefinition() method
protected Cons getDefinition(FactorInterpreter interp)
throws FactorCompilerException
{
Cons definition = toList(interp);
while(definition != null
&& definition.car instanceof FactorDocComment)
definition = definition.next();
return definition;
} //}}}
//{{{ compileCallTo() method
/**
* Compile a call to this word. Returns maximum JVM stack use.
*/
public void compileCallTo(CodeVisitor mw, FactorCompiler compiler,
RecursiveState recursiveCheck) throws Exception
{
// normal word
String defclass;
String defmethod;
StackEffect effect;
FactorClassLoader loader;
RecursiveForm rec = recursiveCheck.get(word);
if(rec != null && rec.active)
{
if(compiler.interp.verboseCompile)
System.err.println("Recursive call to " + rec);
effect = StackEffect.decompose(rec.effect,rec.baseCase);
// are we recursing back on a form inside the current
// method?
RecursiveForm last = recursiveCheck.last();
if(mw != null
&& recursiveCheck.allTails(rec)
&& last.className.equals(rec.className)
&& last.method.equals(rec.method))
{
if(compiler.interp.verboseCompile)
System.err.println(word + " is tail recursive");
// GOTO instad of INVOKEVIRTUAL; ie a loop!
compiler.normalizeStacks(mw);
mw.visitJumpInsn(GOTO,rec.label);
compiler.apply(effect);
return;
}
/* recursive method call! */
defclass = rec.className;
defmethod = rec.method;
loader = rec.loader;
if(mw != null && !defclass.equals(compiler.className))
compiler.loader.addDependency(defclass,loader);
}
else if(mw == null)
{
Cons definition = getDefinition(compiler.interp);
compiler.getStackEffect(definition,recursiveCheck);
return;
}
// not a recursive call but we're still not compiled
// its a bug in the compiler.
else if(this instanceof FactorCompoundDefinition)
{
throw new FactorCompilerException("You are an idiot!");
}
/* ordinary method call! */
else
{
defclass = getClass().getName().replace('.','/');
defmethod = "core";
effect = getStackEffect(compiler.interp,
new RecursiveState());
ClassLoader l = getClass().getClassLoader();
if(l instanceof FactorClassLoader)
{
loader = (FactorClassLoader)l;
compiler.loader.addDependency(
getClass().getName(),loader);
}
else
loader = null;
}
if(mw == null)
compiler.apply(effect);
else
{
mw.visitVarInsn(ALOAD,0);
compiler.generateArgs(mw,effect.inD,effect.inR,null);
String signature = effect.getCorePrototype();
mw.visitMethodInsn(INVOKESTATIC,defclass,defmethod,signature);
compiler.generateReturn(mw,effect.outD,effect.outR);
}
} //}}}
//{{{ compileNonRecursiveImmediate() method
/**
* Non-recursive immediate words are inlined.
*/
protected void compileNonRecursiveImmediate(CodeVisitor mw,
FactorCompiler compiler,
RecursiveState recursiveCheck,
StackEffect immediateEffect) throws Exception
{
Cons definition = toList(compiler.getInterpreter());
Cons endOfDocs = definition;
while(endOfDocs != null
&& endOfDocs.car instanceof FactorDocComment)
endOfDocs = endOfDocs.next();
compiler.compile(endOfDocs,mw,recursiveCheck);
} //}}}
//{{{ compileRecursiveImmediate() method
/**
* Recursive immediate words are compiled to an auxiliary method
* inside the compiled class definition.
*
* This must be done so that recursion has something to jump to.
*/
protected void compileRecursiveImmediate(CodeVisitor mw,
FactorCompiler compiler,
RecursiveState recursiveCheck,
StackEffect immediateEffect) throws Exception
{
Cons definition = toList(compiler.getInterpreter());
Cons endOfDocs = definition;
while(endOfDocs != null
&& endOfDocs.car instanceof FactorDocComment)
endOfDocs = endOfDocs.next();
String method = compiler.auxiliary(word,
endOfDocs,immediateEffect,recursiveCheck);
mw.visitVarInsn(ALOAD,0);
compiler.generateArgs(mw,immediateEffect.inD,
immediateEffect.inR,null);
String signature = immediateEffect.getCorePrototype();
mw.visitMethodInsn(INVOKESTATIC,compiler.className,
method,signature);
compiler.generateReturn(mw,
immediateEffect.outD,
immediateEffect.outR);
} //}}}
//{{{ compileImmediate() method
/**
* Compile a call to this word. Returns maximum JVM stack use.
*/
public void compileImmediate(CodeVisitor mw, FactorCompiler compiler,
RecursiveState recursiveCheck) throws Exception
{
Cons definition = getDefinition(compiler.interp);
if(mw == null)
{
compiler.compile(definition,null,recursiveCheck);
return;
}
// determine stack effect of this instantiation, and if its
// recursive.
FactorArrayStack savedDatastack = (FactorArrayStack)
compiler.datastack.clone();
FactorCallStack savedCallstack = (FactorCallStack)
compiler.callstack.clone();
StackEffect savedEffect = compiler.getStackEffect();
RecursiveState _recursiveCheck = (RecursiveState)
recursiveCheck.clone();
_recursiveCheck.last().effect = compiler.getStackEffect();
compileImmediate(null,compiler,_recursiveCheck);
boolean recursive = (_recursiveCheck.last().baseCase != null);
StackEffect effect = compiler.getStackEffect();
StackEffect immediateEffect = StackEffect.decompose(
savedEffect,compiler.getStackEffect());
// restore previous state.
FactorArrayStack afterDatastack = (FactorArrayStack)
compiler.datastack.clone();
FactorCallStack afterCallstack = (FactorCallStack)
compiler.callstack.clone();
compiler.datastack = (FactorArrayStack)savedDatastack.clone();
compiler.callstack = (FactorCallStack)savedCallstack.clone();
compiler.effect = savedEffect;
if(!recursive)
{
// not recursive; inline.
compileNonRecursiveImmediate(mw,compiler,recursiveCheck,
immediateEffect);
}
else
{
// recursive; must generate auxiliary method.
compileRecursiveImmediate(mw,compiler,recursiveCheck,
immediateEffect);
mergeStacks(savedDatastack,afterDatastack,compiler.datastack);
mergeStacks(savedCallstack,afterCallstack,compiler.callstack);
}
} //}}}
//{{{ mergeStacks() method
private void mergeStacks(FactorArrayStack s1, FactorArrayStack s2,
FactorArrayStack into)
{
for(int i = 0; i < s2.top; i++)
{
if(s1.top <= i)
break;
if(FactorLib.objectsEqual(s1.stack[i],
s2.stack[i]))
{
into.stack[i] = s1.stack[i];
}
}
} //}}}
//{{{ getWorkspace() method
/**
* Each persistent object is stored in one workspace only.
*/
public Workspace getWorkspace()
{
return workspace;
} //}}}
//{{{ getID() method
/**
* Each persistent object has an associated ID.
*/
public long getID()
{
return id;
} //}}}
//{{{ pickle() method
/**
* Each persistent object can turn itself into a byte array.
*/
public byte[] pickle(FactorInterpreter interp)
throws PersistenceException
{
try
{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
Cons pickle = new Cons(word,toList(interp));
bytes.write((FactorReader.getVocabularyDeclaration(pickle)
+ FactorReader.unparseDBObject(pickle))
.getBytes(ENCODING));
return bytes.toByteArray();
}
catch(Exception e)
{
// should not happen with byte array stream
throw new PersistenceException("Unexpected error",e);
}
} //}}}
//{{{ unpickle() method
/**
* Each persistent object can set its state to that in a byte array.
*/
public void unpickle(byte[] bytes, int offset, FactorInterpreter interp)
throws PersistenceException
{
try
{
String unparsed = new String(bytes,offset,
bytes.length - offset,ENCODING);
Cons pickle = (Cons)FactorReader.parseObject(unparsed,
interp);
word = (FactorWord)pickle.car;
fromList(pickle.next(),interp);
}
catch(Exception e)
{
// should not happen with byte array stream
throw new PersistenceException("Unexpected error",e);
}
} //}}}
//{{{ toString() method
public String toString()
{
return getClass().getName() + ": " + word;
} //}}}
}

View File

@ -1,35 +0,0 @@
/* :folding=explicit:collapseFolds=1: */
/*
* $Id$
*
* Copyright (C) 2003 Slava Pestov.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package factor;
public interface PublicCloneable extends Cloneable
{
Object clone();
}

View File

@ -1,983 +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 FactorCompiler implements Constants
{
public final FactorInterpreter interp;
public final FactorWord word;
public final String className;
public final FactorClassLoader loader;
public String method;
private int base;
private int allotD;
private int allotR;
public FactorArrayStack datastack;
public FactorCallStack callstack;
private int literalCount;
private Map literals;
public StackEffect effect;
/**
* getStackEffect() turns these into arrays and places them in the
* returned object.
*/
private Cons inDtypes, inRtypes;
private Cons aux;
private int auxCount;
//{{{ FactorCompiler constructor
/**
* For balancing.
*/
public FactorCompiler(FactorInterpreter interp)
{
this(interp,null,null,null);
init(0,0,0,null);
} //}}}
//{{{ FactorCompiler constructor
/**
* For compiling.
*/
public FactorCompiler(FactorInterpreter interp,
FactorWord word, String className,
FactorClassLoader loader)
{
this.interp = interp;
this.word = word;
this.className = className;
this.loader = loader;
literals = new HashMap();
datastack = new FactorArrayStack();
callstack = new FactorCallStack();
} //}}}
//{{{ getInterpreter() method
public FactorInterpreter getInterpreter()
{
return interp;
} //}}}
//{{{ init() method
public void init(int base, int allotD, int allotR, String method)
{
effect = new StackEffect();
this.base = base;
datastack.top = 0;
callstack.top = 0;
for(int i = 0; i < allotD; i++)
{
Result r = new Result(base + i,this,null,
Object.class);
datastack.push(r);
inDtypes = new Cons(r,inDtypes);
}
for(int i = 0; i < allotR; i++)
{
Result r = new Result(base + allotD + i,this,null,
Object.class);
callstack.push(r);
inRtypes = new Cons(r,inRtypes);
}
this.allotD = allotD;
this.allotR = allotR;
effect.inD = allotD;
effect.inR = allotR;
this.method = method;
} //}}}
//{{{ getAllotedEffect() method
public StackEffect getAllotedEffect()
{
return new StackEffect(allotD,allotR,0,0);
} //}}}
//{{{ ensure() method
public void ensure(FactorArrayStack stack, Class type)
{
if(stack.top == 0)
{
Result r = new Result(allocate(),this,null,type);
if(stack == datastack)
{
inDtypes = new Cons(r,inDtypes);
effect.inD++;
}
else if(stack == callstack)
{
inRtypes = new Cons(r,inRtypes);
effect.inR++;
}
stack.push(r);
}
} //}}}
//{{{ 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)
{
Class[] types = new Class[count];
for(int i = 0; i < types.length; i++)
types[i] = Object.class;
ensure(stack,types);
} //}}}
//{{{ 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, Class[] types)
{
int top = stack.top;
if(top < types.length)
{
Cons typespec = null;
if(stack == datastack)
effect.inD += (types.length - top);
else if(stack == callstack)
effect.inR += (types.length - top);
stack.ensurePush(types.length - top);
System.arraycopy(stack.stack,0,stack.stack,
types.length - top,top);
for(int i = 0; i < types.length - top; i++)
{
int local = allocate();
Result r = new Result(
local,this,null,types[i]);
stack.stack[i] = r;
typespec = new Cons(r,typespec);
}
stack.top = types.length;
if(stack == datastack)
inDtypes = Cons.nappend(inDtypes,typespec);
else if(stack == callstack)
inRtypes = Cons.nappend(inRtypes,typespec);
}
} //}}}
//{{{ 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++)
{
int local = allocate();
stack.push(new Result(local,this,null,Object.class));
}
} //}}}
//{{{ apply() method
public void apply(StackEffect se)
{
consume(datastack,se.inD);
produce(datastack,se.outD);
consume(callstack,se.inR);
produce(callstack,se.outR);
} //}}}
//{{{ getTypeSpec() method
private Class[] getTypeSpec(Cons list)
{
if(list == null)
return new Class[0];
int length = list.length();
Class[] typespec = new Class[length];
int i = 0;
while(list != null)
{
typespec[length - i - 1]
= ((FlowObject)list.car).getType();
i++;
list = list.next();
}
return typespec;
} //}}}
//{{{ getStackEffect() method
public StackEffect getStackEffect()
{
effect.inDtypes = getTypeSpec(inDtypes);
effect.outD = datastack.top;
effect.outDtypes = new Class[datastack.top];
for(int i = 0; i < datastack.top; i++)
{
effect.outDtypes[i] = ((FlowObject)datastack.stack[i])
.getType();
}
effect.inRtypes = getTypeSpec(inRtypes);
effect.outR = callstack.top;
effect.outRtypes = new Class[callstack.top];
for(int i = 0; i < callstack.top; i++)
{
effect.outRtypes[i] = ((FlowObject)callstack.stack[i])
.getType();
}
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)
getStackEffectOfWord((FactorWord)obj,recursiveCheck);
else
pushLiteral(obj,recursiveCheck);
definition = definition.next();
}
} //}}}
//{{{ getStackEffectOfWord() method
private void getStackEffectOfWord(FactorWord word,
RecursiveState recursiveCheck)
throws Exception
{
RecursiveForm rec = recursiveCheck.get(word);
try
{
boolean recursiveCall;
if(rec == null)
{
recursiveCall = false;
recursiveCheck.add(word,
getStackEffect(),
className,loader,
"core");
/* recursiveCheck.last().tail
= (word.def instanceof FactorPrimitiveDefinition); */
}
else
{
recursiveCall = true;
rec.active = true;
}/*
if(rec == null)
recursiveCheck.add(word,getStackEffect(),null,null,null);
else
rec.active = true; */
compileCallTo(word,null,recursiveCheck,false);
}
finally
{
if(rec == null)
recursiveCheck.remove(word);
else
{
rec.active = false;
rec.tail = false;
}
}
} //}}}
//{{{ compileCore() method
public void compileCore(Cons definition, ClassWriter cw,
StackEffect effect, RecursiveState recursiveCheck)
throws Exception
{
RecursiveForm last = recursiveCheck.last();
last.method = "core";
last.className = className;
last.loader = loader;
compileMethod(definition,cw,"core",effect,word,recursiveCheck,true);
} //}}}
//{{{ compileFieldInit() method
private void compileFieldInit(CodeVisitor mw, Label start)
{
mw.visitFieldInsn(GETSTATIC,className,"initialized","Z");
mw.visitJumpInsn(IFNE,start);
mw.visitInsn(ICONST_1);
mw.visitFieldInsn(PUTSTATIC,className,"initialized","Z");
mw.visitVarInsn(ALOAD,0);
mw.visitMethodInsn(INVOKESTATIC,className,"setFields",
"(Lfactor/FactorInterpreter;)V");
} //}}}
//{{{ compileReturn() method
/**
* Once the word finishes executing, any return values need to be
* passed up.
*/
private void compileReturn(CodeVisitor mw, Label end,
StackEffect effect) throws Exception
{
// special case where return value is passed on
// JVM operand stack
// note: in each branch, must visit end label before RETURN!
if(effect.outD == 0 && effect.outR == 0)
{
mw.visitLabel(end);
mw.visitInsn(RETURN);
}
else if(effect.outD == 1 && effect.outR == 0)
{
pop(datastack,mw,Object.class);
mw.visitLabel(end);
mw.visitInsn(ARETURN);
}
else
{
// store datastack in a local
mw.visitVarInsn(ALOAD,0);
mw.visitFieldInsn(GETFIELD,
"factor/FactorInterpreter",
"datastack",
"Lfactor/FactorArrayStack;");
int datastackLocal = allocate();
mw.visitVarInsn(ASTORE,datastackLocal);
for(int i = 0; i < datastack.top; i++)
{
mw.visitVarInsn(ALOAD,datastackLocal);
((FlowObject)datastack.stack[i])
.pop(mw,Object.class);
mw.visitMethodInsn(INVOKEVIRTUAL,
"factor/FactorArrayStack",
"push",
"(Ljava/lang/Object;)V");
}
datastack.top = 0;
// store callstack in a local
mw.visitVarInsn(ALOAD,0);
mw.visitFieldInsn(GETFIELD,
"factor/FactorInterpreter",
"callstack",
"Lfactor/FactorCallStack;");
int callstackLocal = allocate();
mw.visitVarInsn(ASTORE,callstackLocal);
for(int i = 0; i < callstack.top; i++)
{
mw.visitVarInsn(ALOAD,callstackLocal);
((FlowObject)callstack.stack[i])
.pop(mw,Object.class);
mw.visitMethodInsn(INVOKEVIRTUAL,
"factor/FactorCallStack",
"push",
"(Ljava/lang/Object;)V");
}
callstack.top = 0;
mw.visitLabel(end);
mw.visitInsn(RETURN);
}
} //}}}
//{{{ compileMethod() method
/**
* Compiles a method.
*/
public void compileMethod(Cons definition, ClassWriter cw,
String methodName, StackEffect effect, FactorWord word,
RecursiveState recursiveCheck, boolean fieldInit)
throws Exception
{
String signature = effect.getCorePrototype();
CodeVisitor mw = cw.visitMethod(ACC_PUBLIC | ACC_STATIC,
methodName,signature,null,null);
Label start = recursiveCheck.get(word).label;
if(fieldInit)
compileFieldInit(mw,start);
mw.visitLabel(start);
compile(definition,mw,recursiveCheck);
Label end = new Label();
compileReturn(mw,end,effect);
compileExceptionHandler(mw,start,end,word);
mw.visitMaxs(0,0);
} //}}}
//{{{ compileExceptionHandler() method
private void compileExceptionHandler(CodeVisitor mw,
Label start, Label end, FactorWord word)
{
// otherwise no code can throw exception etc
if(start.getOffset() != end.getOffset())
{
// Now compile exception handler.
Label target = new Label();
mw.visitLabel(target);
mw.visitVarInsn(ASTORE,1);
mw.visitVarInsn(ALOAD,0);
mw.visitFieldInsn(GETSTATIC,className,literal(word),
"Ljava/lang/Object;");
mw.visitTypeInsn(CHECKCAST,"factor/FactorWord");
mw.visitVarInsn(ALOAD,1);
mw.visitMethodInsn(INVOKEVIRTUAL,"factor/FactorInterpreter",
"compiledException",
"(Lfactor/FactorWord;Ljava/lang/Throwable;)V");
mw.visitVarInsn(ALOAD,1);
mw.visitInsn(ATHROW);
mw.visitTryCatchBlock(start,end,target,"java/lang/Throwable");
}
} //}}}
//{{{ compile() method
/**
* Compiles a quotation.
*/
public void compile(Cons definition, CodeVisitor mw,
RecursiveState recursiveCheck) throws Exception
{
while(definition != null)
{
Object obj = definition.car;
if(obj instanceof FactorWord)
{
compileWord((FactorWord)obj,mw,recursiveCheck,
definition.cdr == null);
}
else
pushLiteral(obj,recursiveCheck);
definition = definition.next();
}
} //}}}
//{{{ compileWord() method
private void compileWord(FactorWord w, CodeVisitor mw,
RecursiveState recursiveCheck,
boolean tail) throws Exception
{
if(tail && interp.verboseCompile)
System.err.println("Tail: " + recursiveCheck.last());
recursiveCheck.last().tail = tail;
RecursiveForm rec = recursiveCheck.get(w);
try
{
boolean recursiveCall;
if(rec == null)
{
recursiveCall = false;
recursiveCheck.add(w,
new StackEffect(),
className,loader,
"core");
recursiveCheck.last().tail
= (w.def instanceof FactorPrimitiveDefinition);
}
else
{
recursiveCall = true;
rec.active = true;
}
compileCallTo(w,mw,recursiveCheck,recursiveCall);
}
finally
{
if(rec == null)
recursiveCheck.remove(w);
else
{
rec.active = false;
rec.tail = false;
}
}
} //}}}
//{{{ compileCallTo() method
private void compileCallTo(FactorWord w, CodeVisitor mw,
RecursiveState recursiveCheck,
boolean recursiveCall) throws Exception
{
if(w.def == null)
throw new FactorUndefinedWordException(w);
FactorWordDefinition d = w.def;
if(!recursiveCall)
{
StackEffect effect = getStackEffectOrNull(d);
if(w.inline)
{
d.compileImmediate(mw,this,recursiveCheck);
return;
}
else if(d instanceof FactorCompoundDefinition
&& mw != null)
{
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;
}
d.compileCallTo(mw,this,recursiveCheck);
} //}}}
//{{{ push() method
/**
* Generates code for pushing the top of the JVM stack onto the
* data stack. Also generates code for converting this value to
* the given type.
*/
public void push(FactorArrayStack stack, CodeVisitor mw, Class type)
throws Exception
{
int local = allocate();
Result r = new Result(local,this,null,type);
stack.push(r);
r.push(mw,type);
} //}}}
//{{{ 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));
}
} //}}}
//{{{ pop() method
/**
* Generates code for popping the top of the data stack onto
* the JVM stack. Also generates code for converting this value to
* the given type.
*/
public void pop(FactorArrayStack stack, CodeVisitor mw, Class type)
throws Exception
{
FlowObject obj = (FlowObject)datastack.pop();
obj.pop(mw,type);
} //}}}
//{{{ 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))
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;
} //}}}
//{{{ auxiliary() method
public String auxiliary(FactorWord word, Cons code, StackEffect effect,
RecursiveState recursiveCheck) throws Exception
{
FactorArrayStack savedDatastack = (FactorArrayStack)
datastack.clone();
FactorCallStack savedCallstack = (FactorCallStack)
callstack.clone();
String method = "aux_" + FactorJava.getSanitizedName(word.name)
+ "_" + (auxCount++);
recursiveCheck.last().method = method;
aux = new Cons(new AuxiliaryQuotation(
method,savedDatastack,savedCallstack,
code,effect,word,this,recursiveCheck),aux);
return method;
} //}}}
//{{{ generateAuxiliary() method
public void generateAuxiliary(ClassWriter cw) throws Exception
{
while(aux != null)
{
AuxiliaryQuotation q = (AuxiliaryQuotation)aux.car;
// order of these two important, in case
// compilation of q adds more quotations to aux list
aux = aux.next();
q.compile(this,cw);
}
} //}}}
//{{{ normalizeStacks() method
public void normalizeStacks(CodeVisitor mw)
throws Exception
{
int datastackTop = datastack.top;
datastack.top = 0;
int callstackTop = callstack.top;
callstack.top = 0;
localsToStack(callstack,callstackTop,mw);
localsToStack(datastack,datastackTop,mw);
stackToLocals(datastack,datastackTop,mw);
stackToLocals(callstack,callstackTop,mw);
} //}}}
//{{{ localsToStack() method
private void localsToStack(FactorArrayStack stack, int top,
CodeVisitor mw)
{
for(int i = top - 1; i >= 0; i--)
{
FlowObject obj = (FlowObject)stack.stack[i];
obj.pop(mw);
}
} //}}}
//{{{ stackToLocals() method
private void stackToLocals(FactorArrayStack stack, int top,
CodeVisitor mw) throws Exception
{
for(int i = 0; i < top; i++)
push(stack,mw,Object.class);
} //}}}
//{{{ 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 inD, int inR, Class[] args)
throws Exception
{
for(int i = 0; i < inD; i++)
{
FlowObject obj = (FlowObject)datastack.stack[
datastack.top - inD + i];
obj.pop(mw,args == null ? Object.class : args[i]);
}
datastack.top -= inD;
for(int i = 0; i < inR; i++)
{
FlowObject obj = (FlowObject)callstack.stack[
callstack.top - inR + i];
obj.pop(mw,args == null ? Object.class : args[i]);
}
callstack.top -= inR;
} //}}}
//{{{ generateReturn() method
public void generateReturn(CodeVisitor mw, int outD, int outR)
throws Exception
{
if(outD == 0 && outR == 0)
{
// do nothing
}
else if(outD == 1 && outR == 0)
{
push(datastack,mw,Object.class);
}
else
{
// transfer from data stack to JVM locals
// allocate the appropriate number of locals
if(outD != 0)
{
produce(datastack,outD);
// store the datastack instance somewhere
mw.visitVarInsn(ALOAD,0);
mw.visitFieldInsn(GETFIELD,
"factor/FactorInterpreter",
"datastack",
"Lfactor/FactorArrayStack;");
int datastackLocal = allocate();
mw.visitVarInsn(ASTORE,datastackLocal);
// put all elements from the real datastack
// into locals
for(int i = 0; i < outD; i++)
{
mw.visitVarInsn(ALOAD,datastackLocal);
mw.visitMethodInsn(INVOKEVIRTUAL,
"factor/FactorArrayStack",
"pop",
"()Ljava/lang/Object;");
Result destination = (Result)
datastack.stack[
datastack.top - i - 1];
destination.push(mw,Object.class);
}
}
if(outR != 0)
{
produce(callstack,outR);
mw.visitVarInsn(ALOAD,0);
mw.visitFieldInsn(GETFIELD,
"factor/FactorInterpreter",
"callstack",
"Lfactor/FactorCallStack;");
int callstackLocal = allocate();
mw.visitVarInsn(ASTORE,callstackLocal);
// put all elements from the real callstack
// into locals
for(int i = 0; i < outR; i++)
{
mw.visitVarInsn(ALOAD,callstackLocal);
mw.visitMethodInsn(INVOKEVIRTUAL,
"factor/FactorCallStack",
"pop",
"()Ljava/lang/Object;");
Result destination = (Result)
callstack.stack[
callstack.top - i - 1];
destination.push(mw,Object.class);
}
}
}
} //}}}
//{{{ generateFields() method
public void generateFields(ClassWriter cw)
throws Exception
{
for(int i = 0; i < literalCount; i++)
{
cw.visitField(ACC_PRIVATE | ACC_STATIC,"literal_" + i,
"Ljava/lang/Object;",null,null);
}
CodeVisitor mw = cw.visitMethod(ACC_PRIVATE | ACC_STATIC,
"setFields","(Lfactor/FactorInterpreter;)V",null,null);
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();
generateParse(mw,literal,0);
mw.visitFieldInsn(PUTSTATIC,
className,
"literal_" + index,
"Ljava/lang/Object;");
}
mw.visitInsn(RETURN);
mw.visitMaxs(0,0);
} //}}}
//{{{ generateParse() method
public void generateParse(CodeVisitor mw, Object obj, int interpLocal)
{
mw.visitLdcInsn(FactorReader.getVocabularyDeclaration(obj)
+ FactorReader.unparseObject(obj));
mw.visitVarInsn(ALOAD,interpLocal);
mw.visitMethodInsn(INVOKESTATIC,
"factor/FactorReader",
"parseObject",
"(Ljava/lang/String;Lfactor/FactorInterpreter;)"
+ "Ljava/lang/Object;");
} //}}}
//{{{ getStackEffectOrNull() method
public StackEffect getStackEffectOrNull(FactorWordDefinition def)
{
try
{
return def.getStackEffect(interp,
new RecursiveState());
}
catch(Exception e)
{
//System.err.println("WARNING: " + e);
//System.err.println(def);
return null;
}
} //}}}
//{{{ getStackEffectOrNull() method
public 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

@ -39,15 +39,12 @@ import sidekick.*;
public class FactorAsset extends Asset
{
private FactorWord word;
private FactorWordDefinition def;
public FactorAsset(FactorWord word, FactorWordDefinition def,
Position start)
public FactorAsset(FactorWord word, Position start)
{
super(word.name);
this.start = start;
this.word = word;
this.def = def;
this.start = start;
}
public Icon getIcon()
@ -62,6 +59,6 @@ public class FactorAsset extends Asset
public String getLongString()
{
return FactorWordRenderer.getWordHTMLString(word,def,false);
return FactorWordRenderer.getWordHTMLString(word,false);
}
}

View File

@ -43,11 +43,11 @@ sidekick.parser.factor.label=Factor
mode.factor.sidekick.parser=factor
factor.completion.in=<font color="#a0a0a0">IN: {0}</font>\
factor.completion.plain=: <b>{0}</b>
factor.completion.colon=: <b>{0}</b>
factor.completion.defer=DEFER: <b>{0}</b>
factor.completion.parsing=PARSING: <b>{0}</b>
factor.completion.stack=: <b>{0}</b> {1}
factor.completion.symbol=SYMBOL: <b>{0}</b>
factor.completion.stack={0} ({1})
# Dialog boxes
factor.status.inserted-use=Inserted {0}

View File

@ -40,7 +40,6 @@ import sidekick.*;
public class FactorSideKickParser extends SideKickParser
{
private WordPreview wordPreview;
private Map previewMap;
/**
@ -55,22 +54,6 @@ public class FactorSideKickParser extends SideKickParser
{
super("factor");
previewMap = new HashMap();
worddefs = new HashMap();
} //}}}
//{{{ getWordDefinition() method
/**
* Check for a word definition from a parsed source file. If one is
* found, return it, otherwise return interpreter's definition.
*/
public FactorWordDefinition getWordDefinition(FactorWord word)
{
FactorWordDefinition def = (FactorWordDefinition)
worddefs.get(word);
if(def != null)
return def;
else
return word.def;
} //}}}
//{{{ activate() method
@ -180,7 +163,6 @@ public class FactorSideKickParser extends SideKickParser
parsed.car;
FactorWord word = def.word;
worddefs.put(word,def);
/* word lines are indexed from 1 */
int startLine = Math.min(
@ -197,8 +179,7 @@ public class FactorSideKickParser extends SideKickParser
if(last != null)
last.end = buffer.createPosition(start - 1);
last = new FactorAsset(word,def,
buffer.createPosition(start));
last = new FactorAsset(word,buffer.createPosition(start));
d.root.add(new DefaultMutableTreeNode(last));
}

View File

@ -37,13 +37,11 @@ import org.gjt.sp.jedit.*;
public class FactorWordRenderer extends DefaultListCellRenderer
{
//{{{ getWordHTMLString() method
public static String getWordHTMLString(FactorWord word,
FactorWordDefinition def, boolean showIn)
public static String getWordHTMLString(FactorWord word, boolean showIn)
{
String prop = "factor.completion.plain";
String stackEffect = null;
String prop = "factor.completion.colon";
if(def == null)
/* if(def == null)
{
if(word.parsing != null)
prop = "factor.completion.parsing";
@ -63,11 +61,10 @@ public class FactorWordRenderer extends DefaultListCellRenderer
d.car;
if(comment.isStackComment())
{
prop = "factor.completion.stack";
stackEffect = comment.toString();
}
}
}
} */
String in;
if(showIn)
@ -80,13 +77,15 @@ public class FactorWordRenderer extends DefaultListCellRenderer
else
in = "";
return "<html>" + in + jEdit.getProperty(prop,
new Object[] {
MiscUtilities.charsToEntities(word.name),
stackEffect == null
? null :
MiscUtilities.charsToEntities(stackEffect)
});
String html = "<html>" + in + jEdit.getProperty(prop,
new Object[] { MiscUtilities.charsToEntities(word.name) });
if(word.stackEffect != null)
{
html += jEdit.getProperty("factor.completion.stack",
new String[] { html, word.stackEffect });
}
return html;
} //}}}
private FactorSideKickParser parser;
@ -114,9 +113,7 @@ public class FactorWordRenderer extends DefaultListCellRenderer
return this;
FactorWord word = (FactorWord)value;
setText(getWordHTMLString(word,
parser.getWordDefinition(word),
showIn));
setText(getWordHTMLString(word,showIn));
return this;
} //}}}

View File

@ -125,7 +125,7 @@ public class WordPreview implements ActionListener, CaretListener
{
view.getStatus().setMessageAndClear(
FactorWordRenderer.getWordHTMLString(
w,fdata.parser.getWordDefinition(w),true));
w,true));
}
}
catch(IOException e)

View File

@ -49,10 +49,13 @@ public class Ine extends FactorParsingDefinition
throws Exception
{
FactorReader.ParseState state = reader.popState(start,word);
FactorWord w = (FactorWord)state.arg;
FactorWord w = state.defining;
/* Only ever null with restartable scanner;
error already logged, so give up */
if(w == null)
return;
reader.append(new FactorCompoundDefinition(w,state.first));
w.def = new FactorCompoundDefinition(w,state.first);
reader.append(w.def);
}
}

View File

@ -51,6 +51,6 @@ public class LineComment extends FactorParsingDefinition
{
String comment = reader.getScanner().readUntilEOL();
if(doc)
reader.append(new FactorDocComment(comment,false));
reader.addDocComment(comment);
}
}

View File

@ -47,6 +47,6 @@ public class StackComment extends FactorParsingDefinition
throws Exception
{
String comment = reader.getScanner().readUntil( '(',')',false);
reader.append(new FactorDocComment(comment,true));
reader.setStackComment(comment);
}
}

View File

@ -46,6 +46,7 @@ public class Symbol extends FactorParsingDefinition
throws Exception
{
FactorWord w = reader.nextWord(true);
reader.append(new FactorSymbolDefinition(w,w));
w.def = new FactorSymbolDefinition(w,w);
reader.append(w.def);
}
}