View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View
@@ -0,0 +1,91 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
grammar Smalltalk;
script : sequence ws EOF;
sequence : temps? ws statements? ws;
ws : (SEPARATOR | COMMENT)*;
temps : ws PIPE (ws IDENTIFIER)+ ws PIPE;
statements : answer ws # StatementAnswer
| expressions ws PERIOD ws answer # StatementExpressionsAnswer
| expressions PERIOD? ws # StatementExpressions
;
answer : CARROT ws expression ws PERIOD?;
expression : assignment | cascade | keywordSend | binarySend | primitive;
expressions : expression expressionList*;
expressionList : PERIOD ws expression;
cascade : (keywordSend | binarySend) (ws SEMI_COLON ws message)+;
message : binaryMessage | unaryMessage | keywordMessage;
assignment : variable ws ASSIGNMENT ws expression;
variable : IDENTIFIER;
binarySend : unarySend binaryTail?;
unarySend : operand ws unaryTail?;
keywordSend : binarySend keywordMessage;
keywordMessage : ws (keywordPair ws)+;
keywordPair : KEYWORD ws binarySend ws;
operand : literal | reference | subexpression;
subexpression : OPEN_PAREN ws expression ws CLOSE_PAREN;
literal : runtimeLiteral | parsetimeLiteral;
runtimeLiteral : dynamicDictionary | dynamicArray | block;
block : BLOCK_START blockParamList? ws (PIPE ws)? sequence BLOCK_END;
blockParamList : (ws BLOCK_PARAM)+;
dynamicDictionary : DYNDICT_START ws expressions? ws DYNARR_END;
dynamicArray : DYNARR_START ws expressions? ws DYNARR_END;
parsetimeLiteral : charConstant | pseudoVariable | number | literalArray | string | symbol;
number : numberExp | hex | stFloat | stInteger;
numberExp : (stFloat | stInteger) EXP stInteger;
charConstant : CHARACTER_CONSTANT;
hex : MINUS? HEX HEXDIGIT+;
stInteger : MINUS? DIGIT+;
stFloat : MINUS? DIGIT+ PERIOD DIGIT+;
pseudoVariable : RESERVED_WORD;
string : STRING;
symbol : HASH bareSymbol;
primitive : LT ws KEYWORD ws DIGIT+ ws GT;
bareSymbol : (IDENTIFIER | BINARY_SELECTOR) | KEYWORD+ | string | PIPE+;
literalArray : LITARR_START literalArrayRest;
literalArrayRest : (ws (parsetimeLiteral | bareLiteralArray | bareSymbol))* ws CLOSE_PAREN;
bareLiteralArray : OPEN_PAREN literalArrayRest;
unaryTail : unaryMessage ws unaryTail? ws;
unaryMessage : ws unarySelector;
unarySelector : IDENTIFIER;
keywords : KEYWORD+;
reference : variable;
binaryTail : binaryMessage binaryTail?;
binaryMessage : ws BINARY_SELECTOR ws (unarySend | operand);
SEPARATOR : [ \t\r\n];
STRING : '\'' (.)*? '\'';
COMMENT : '"' (.)*? '"';
BLOCK_START : '[';
BLOCK_END : ']';
CLOSE_PAREN : ')';
OPEN_PAREN : '(';
PIPE : '|';
PERIOD : '.';
SEMI_COLON : ';';
BINARY_SELECTOR : ('\\' | '+' | '*' | '/' | '=' | '>' | '<' | ',' | '@' | '%' | '~' | PIPE | '&' | '-' | '?')+;
LT : '<';
GT : '>';
MINUS : '-';
RESERVED_WORD : 'nil' | 'true' | 'false' | 'self' | 'super';
IDENTIFIER : [a-zA-Z]+[a-zA-Z0-9_]*;
CARROT : '^';
COLON : ':';
ASSIGNMENT : ':=';
HASH : '#';
DOLLAR : '$';
EXP : 'e';
HEX : '16r';
LITARR_START : '#(';
DYNDICT_START : '#{';
DYNARR_END : '}';
DYNARR_START : '{';
DIGIT : [0-9];
HEXDIGIT : [0-9a-fA-F];
KEYWORD : IDENTIFIER COLON;
BLOCK_PARAM : COLON IDENTIFIER;
CHARACTER_CONSTANT : DOLLAR .;
View
@@ -0,0 +1,5 @@
java -jar ../../../lib/antlr-4.1-complete.jar -o ../java/st/redline/compiler -no-listener -visitor -package st.redline.compiler Smalltalk.g4
# byte[] generatedClassBytes(); SmalltalkVisitor
# public byte[] generatedClassBytes() { return null; } SmalltalkBaseVisitor
View
@@ -0,0 +1,3 @@
ExampleClass class methodAt: #sayHello put: [
Transcript show: 'Hello World.'; cr.
].
View
@@ -0,0 +1,3 @@
ExampleClass methodAt: #sayHello put: [
Transcript show: 'Hello World.'; cr.
].
View
@@ -0,0 +1,3 @@
ExampleClass methodAt: #sayHello put: [ | foo bar |
Transcript show: 'Hello World.'; cr.
].
View
@@ -0,0 +1,3 @@
ExampleClass methodAt: #sayHello put: [ :arg1 :arg2 | tmp1 tmp2 |
Transcript show: 'Hello World.'; cr.
].
View
@@ -0,0 +1 @@
^ [].
View
@@ -0,0 +1 @@
^ [ ].
View
@@ -0,0 +1 @@
a := 123
View
@@ -0,0 +1 @@
[ :foo :bar | ^ self. ]
View
@@ -0,0 +1 @@
[ :foo :bar | baz | ]
View
@@ -0,0 +1 @@
[ :foo :bar | baz | ^ self ]
View
@@ -0,0 +1 @@
[ | baz | ]
View
@@ -0,0 +1,4 @@
Transcript
open;
show: 'message';
cr
View
@@ -0,0 +1,7 @@
Transcript
open;
show: 10;
show: #Symbol;
show: #(123 $X 'hello' Sunday);
show: $E;
cr
View
@@ -0,0 +1 @@
a == nil ifTrue: [].
View
@@ -0,0 +1,6 @@
(a == nil)
ifTrue: [
^ true
] ifFalse: [
^ false
]
View
@@ -0,0 +1 @@
b < (a - c) ifTrue: [ ^ true ]
View
No changes.
View
@@ -0,0 +1 @@
[]
View
@@ -0,0 +1 @@
[ ]
View
@@ -0,0 +1 @@
#( 1234 $E 'hello' Symbol $$ $; $4 $. )
View
@@ -0,0 +1 @@
#()
View
@@ -0,0 +1 @@
| foo bar |
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View
@@ -1,55 +1,75 @@
/* Redline Smalltalk, Copyright (c) James C. Ladd. All rights reserved. See LICENSE in the root of this distribution. */
package st.redline;
import st.redline.classloader.*;
import java.io.*;
public class Stic {
private SticConfiguration configuration;
private final String[] args;
public static void main(String[] args) throws Exception {
new Stic(args).run();
}
public Stic(String[] args) {
this.args = args;
}
private void run() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
run(loadScript(scriptName()));
}
private void run(Class cls) throws IllegalAccessException, InstantiationException {
cls.newInstance();
}
public static void main(String[] args) {
SticConfiguration configuration = configuration(args);
try {
new Stic(configuration).run();
} catch (Exception e) {
print(e.getCause() != null ? e.getCause() : e);
}
private Class loadScript(String name) throws ClassNotFoundException {
return classLoader().loadScript(name);
}
private static void print(Throwable throwable) {
throwable.printStackTrace();
private SmalltalkClassLoader classLoader() {
return new SmalltalkClassLoader(currentClassLoader(), sourceFinder(), bootstrapper());
}
private static SticConfiguration configuration(String[] args) {
return new SticConfiguration(args);
private Bootstrapper bootstrapper() {
return new Bootstrapper();
}
public Stic(SticConfiguration configuration) {
this.configuration = configuration;
private SourceFinder sourceFinder() {
return new SmalltalkSourceFinder(sourceFactory(), classPaths());
}
public void run() throws Exception {
runProgram(scriptName());
private SourceFactory sourceFactory() {
return new SourceFactory();
}
private void runProgram(String program) throws Exception {
run(loadProgram(program));
public String[] classPaths() {
return classPath().split(File.pathSeparator);
}
private void run(Class aClass) throws Exception {
if (aClass != null)
aClass.newInstance();
private String classPath() {
return System.getProperty("java.class.path");
}
public Class loadProgram(String program) throws Exception {
ClassLoader classLoader = classLoader();
return Class.forName(program, true, classLoader);
private ClassLoader currentClassLoader() {
return Thread.currentThread().getContextClassLoader();
}
private String scriptName() {
String scriptName = configuration.scriptName();
return "".equals(scriptName) ? "st.redline.NoScript" : scriptName;
return hasArguments() ? firstArgument() : defaultScriptName();
}
private String defaultScriptName() {
return "st.redline.script.NoArguments";
}
private String firstArgument() {
return args[0];
}
private ClassLoader classLoader() throws Exception {
return configuration.classLoader();
private boolean hasArguments() {
return args.length > 0;
}
}
View

This file was deleted.

Oops, something went wrong.
View
@@ -1,104 +1,143 @@
/* Redline Smalltalk, Copyright (c) James C. Ladd. All rights reserved. See LICENSE in the root of this distribution. */
package st.redline.classloader;
import st.redline.lang.*;
import st.redline.core.*;
import java.io.File;
import static st.redline.core.PrimSubclass.PRIM_SUBCLASS;
public class Bootstrapper {
private final SourceFinder sourceFinder;
public void bootstrap(SmalltalkClassLoader classLoader) {
setContextClassLoader(classLoader);
public Bootstrapper(SourceFinder sourceFinder) {
this.sourceFinder = sourceFinder;
classLoader.beginBootstrapping();
createPrimObject(classLoader);
createKernelObjectsHierarchy(classLoader);
classLoader.importAll("st.redline.kernel");
loadKernelObjects(classLoader);
classLoader.endBootstrapping();
}
public void bootstrap(SmalltalkClassLoader smalltalkClassLoader) throws Exception {
bootstrapNil(smalltalkClassLoader);
bootstrapMetaclass(smalltalkClassLoader);
bootstrapProtoObject(smalltalkClassLoader);
bootstrapSymbol(smalltalkClassLoader);
bootstrapObject(smalltalkClassLoader);
bootstrapMetaclassHierarchy(smalltalkClassLoader);
smalltalkClassLoader.stoppedBootstrapping();
bootstrapNilHierarchy(smalltalkClassLoader);
bootstrapBooleans(smalltalkClassLoader);
private void createKernelObjectsHierarchy(SmalltalkClassLoader classLoader) {
// Create Kernel Objects and Classes we need to start Runtime.
PrimObject primObject = classLoader.cachedObject("st.redline.kernel.PrimObject");
PrimClass object = createKernelObject("Object", primObject);
PrimClass behavior = createKernelObject("Behavior", object);
PrimClass classDescription = createKernelObject("ClassDescription", behavior);
PrimClass klass = createKernelObject("Class", classDescription);
PrimClass metaclass = createKernelObject("Metaclass", classDescription);
PrimClass undefinedObject = createKernelObject("UndefinedObject", object, metaclass);
PrimClass blockClosure = createKernelObject("BlockClosure", object, metaclass);
PrimClass compiledMethod = createKernelObject("CompiledMethod", object, metaclass);
PrimClass booleanObject = createKernelObject("Boolean", object, metaclass);
PrimClass trueObject = createKernelObject("True", booleanObject, metaclass);
PrimClass falseObject = createKernelObject("False", booleanObject, metaclass);
PrimClass collection = createKernelObject("Collection", object, metaclass);
PrimClass sequenceableCollection = createKernelObject("SequenceableCollection", collection, metaclass);
PrimClass arrayedCollection = createKernelObject("ArrayedCollection", sequenceableCollection, metaclass);
PrimClass string = createKernelObject("String", arrayedCollection, metaclass);
PrimClass symbol = createKernelObject("Symbol", string, metaclass);
// Fix up bootstrapped Kernel Objects Metaclass instance.
klass.selfClass().selfClass(metaclass);
classDescription.selfClass().selfClass(metaclass);
behavior.selfClass().selfClass(metaclass);
object.selfClass().selfClass(metaclass);
// Initialise special Smalltalk circular hierarchy.
((PrimClass) object.selfClass()).superclass(klass);
// Let subclass primitive know the Metaclass instance - used when subclassing.
((PrimSubclass) PRIM_SUBCLASS).metaclass(metaclass);
// Add basicAddSelector:withMethod: to Behaviour
((PrimClass) behavior).addMethod("basicAddSelector:withMethod:", new PrimAddMethod());
// Create special instances, referred to with pseudo variables.
PrimObject nil = new PrimObject();
nil.selfClass(undefinedObject);
classLoader.nilInstance(nil);
PrimObject trueInstance = new PrimObject();
trueInstance.selfClass(trueObject);
classLoader.trueInstance(trueInstance);
PrimObject falseInstance = new PrimObject();
falseInstance.selfClass(falseObject);
classLoader.falseInstance(falseInstance);
// Load the hierarchy which will attached their methods.
classLoader.cacheObject("st.redline.kernel.Object", object);
classLoader.cacheObject("st.redline.kernel.Behavior", behavior);
classLoader.cacheObject("st.redline.kernel.ClassDescription", classDescription);
classLoader.cacheObject("st.redline.kernel.Class", klass);
classLoader.cacheObject("st.redline.kernel.Metaclass", metaclass);
classLoader.cacheObject("st.redline.kernel.UndefinedObject", undefinedObject);
classLoader.cacheObject("st.redline.kernel.BlockClosure", blockClosure);
classLoader.cacheObject("st.redline.kernel.CompiledMethod", compiledMethod);
classLoader.cacheObject("st.redline.kernel.Boolean", booleanObject);
classLoader.cacheObject("st.redline.kernel.True", trueObject);
classLoader.cacheObject("st.redline.kernel.False", falseObject);
classLoader.cacheObject("st.redline.kernel.Collection", collection);
classLoader.cacheObject("st.redline.kernel.SequenceableCollection", sequenceableCollection);
classLoader.cacheObject("st.redline.kernel.ArrayedCollection", arrayedCollection);
classLoader.cacheObject("st.redline.kernel.String", string);
classLoader.cacheObject("st.redline.kernel.Symbol", symbol);
}
private void bootstrapBooleans(SmalltalkClassLoader smalltalkClassLoader) throws Exception {
ProtoObject Metaclass = smalltalkClassLoader.METACLASS;
ProtoObject TrueClass = Metaclass.resolveObject("st.redline.kernel.True");
smalltalkClassLoader.TRUE = TrueClass.perform("new");
ProtoObject FalseClass = Metaclass.resolveObject("st.redline.kernel.False");
smalltalkClassLoader.FALSE = FalseClass.perform("new");
private PrimClass createKernelObject(String name, PrimObject superclass) {
PrimClass primMeta = new PrimClass(name,true);
primMeta.superclass(superclass.selfClass());
PrimClass primClass = new PrimClass(name);
primClass.superclass(superclass);
primClass.selfClass(primMeta);
return primClass;
}
private void bootstrapNilHierarchy(SmalltalkClassLoader smalltalkClassLoader) throws Exception {
ProtoObject Metaclass = smalltalkClassLoader.METACLASS;
smalltalkClassLoader.NIL.selfclass = Metaclass.resolveObject("st.redline.kernel.UndefinedObject");
private PrimClass createKernelObject(String name, PrimObject superclass, PrimObject metaclass) {
PrimClass primClass = createKernelObject(name, superclass);
primClass.selfClass().selfClass(metaclass);
return primClass;
}
private void bootstrapNil(SmalltalkClassLoader smalltalkClassLoader) {
smalltalkClassLoader.NIL = new ProtoObject();
private void setContextClassLoader(SmalltalkClassLoader classLoader) {
Thread.currentThread().setContextClassLoader(classLoader);
}
private void bootstrapMetaclassHierarchy(SmalltalkClassLoader smalltalkClassLoader) throws Exception {
ProtoObject Metaclass = smalltalkClassLoader.METACLASS;
ProtoObject classDescription = Metaclass.resolveObject("st.redline.kernel.ClassDescription");
((ProtoClass) Metaclass).superclass(classDescription);
private void loadKernelObjects(SmalltalkClassLoader classLoader) {
loadObject(classLoader, "st.redline.kernel.Object");
loadObject(classLoader, "st.redline.kernel.Behavior");
loadObject(classLoader, "st.redline.kernel.ClassDescription");
loadObject(classLoader, "st.redline.kernel.Class");
loadObject(classLoader, "st.redline.kernel.Metaclass");
loadObject(classLoader, "st.redline.kernel.UndefinedObject");
loadObject(classLoader, "st.redline.kernel.BlockClosure");
loadObject(classLoader, "st.redline.kernel.CompiledMethod");
loadObject(classLoader, "st.redline.kernel.Boolean");
loadObject(classLoader, "st.redline.kernel.True");
loadObject(classLoader, "st.redline.kernel.False");
loadObject(classLoader, "st.redline.kernel.Collection");
loadObject(classLoader, "st.redline.kernel.SequenceableCollection");
loadObject(classLoader, "st.redline.kernel.ArrayedCollection");
loadObject(classLoader, "st.redline.kernel.String");
loadObject(classLoader, "st.redline.kernel.Symbol");
}
private void bootstrapObject(SmalltalkClassLoader smalltalkClassLoader) throws Exception {
ProtoObject Metaclass = smalltalkClassLoader.METACLASS;
ProtoObject Object = Metaclass.resolveObject("st.redline.kernel.Object");
ProtoObject Class = Metaclass.resolveObject("st.redline.kernel.Class");
((ProtoClass) Object.selfclass).superclass(Class);
private void createPrimObject(SmalltalkClassLoader classLoader) {
PrimObject primObject = new PrimObject();
primObject.selfClass(primObject);
classLoader.cacheObject("st.redline.kernel.PrimObject", primObject);
}
private void bootstrapSymbol(SmalltalkClassLoader smalltalkClassLoader) throws ClassNotFoundException {
smalltalkClassLoader.METACLASS.resolveObject("st.redline.kernel.Symbol");
}
private void bootstrapMetaclass(SmalltalkClassLoader smalltalkClassLoader) {
ProtoClass Metaclass = new ProtoClass();
ProtoClass metaclass = Metaclass.create("Metaclass");
Metaclass.selfclass = metaclass;
smalltalkClassLoader.METACLASS = metaclass;
metaclass.addMethod("atSelector:put:", new PrimAtSelectorPutMethod());
}
private ProtoObject bootstrapProtoObject(SmalltalkClassLoader smalltalkClassLoader) {
ProtoClass ProtoObject = makeProtoObject((ProtoClass) smalltalkClassLoader.METACLASS);
smalltalkClassLoader.registerProtoObject(ProtoObject);
addKernelImports(ProtoObject);
return ProtoObject;
}
private void addKernelImports(ProtoClass protoObject) {
for (Source source : sourceFinder.findIn("st.redline.kernel"))
addKernelImport(protoObject, source);
// TODO.JCL - Do we really have to add all roots?
for (Source source : sourceFinder.findIn("st.redline.test"))
addKernelImport(protoObject, source);
}
private void addKernelImport(ProtoClass protoObject, Source source) {
protoObject.importAtPut(source.className(), source.fullyQualifiedName());
}
private ProtoClass makeProtoObject(ProtoClass metaclass) {
// Create ProtoObject class (metaclass)
ProtoClass protoObjectClass = new ProtoClass();
protoObjectClass.selfclass = metaclass;
// Add methods needed during bootstrap.
protoObjectClass.addMethod("subclass:", new PrimSubclass());
protoObjectClass.addMethod("import:", new PrimImport());
protoObjectClass.addMethod("class", new PrimClass());
protoObjectClass.addMethod("atSelector:put:", new PrimAtSelectorPutMethod());
// Create ProtoObject sole instance. ProtoObject is a class.
ProtoClass protoObject = protoObjectClass.create("ProtoObject");
return protoObject;
private void loadObject(ClassLoader classLoader, String name) {
try {
// Loading and instantiating the class causes the 'sendMessages' java method
// to be called which executes all the message sends of the Smalltalk source.
classLoader.loadClass(name).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
View

This file was deleted.

Oops, something went wrong.
View
@@ -1,28 +1,33 @@
/* Redline Smalltalk, Copyright (c) James C. Ladd. All rights reserved. See LICENSE in the root of this distribution. */
package st.redline.classloader.io;
package st.redline.classloader;
import java.io.*;
public class FileSourceReader implements SourceReader {
private String filename;
private final File file;
public FileSourceReader(String filename) {
this.filename = filename;
public FileSourceReader(File file) {
this.file = file;
}
public String contents() {
public String contents(LineTransformer lineTransformer) {
FileInputStream fis = null;
String newLine = System.getProperty("line.separator");
StringBuilder contents = new StringBuilder();
try {
fis = new FileInputStream(filename);
fis = new FileInputStream(file);
BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
String line;
while ((line = reader.readLine()) != null) {
line = lineTransformer.begin();
if (line != null)
contents.append(line);
contents.append(newLine);
while ((line = reader.readLine()) != null) {
contents.append(lineTransformer.transform(line + newLine));
}
line = lineTransformer.end();
if (line != null)
contents.append(line);
return contents.toString();
} catch (Exception e) {
throw new RuntimeException(e);
View
@@ -1,9 +1,9 @@
/* Redline Smalltalk, Copyright (c) James C. Ladd. All rights reserved. See LICENSE in the root of this distribution. */
package st.redline.classloader.io;
package st.redline.classloader;
import java.io.*;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import java.util.jar.*;
import java.util.zip.*;
public class JarSourceReader implements SourceReader {
@@ -15,7 +15,7 @@ public JarSourceReader(String entryName, String path) {
this.path = path;
}
public String contents() {
public String contents(LineTransformer lineTransformer) {
// TODO.JCL - There is a lot of commonality between this 'contents()' method
// and the one in FileSourceReader - DRY up into SourceReader at some point.
String newLine = System.getProperty("line.separator");
@@ -30,10 +30,15 @@ public String contents() {
InputStreamReader isr = new InputStreamReader(input);
reader = new BufferedReader(isr);
String line;
while ((line = reader.readLine()) != null) {
line = lineTransformer.begin();
if (line != null)
contents.append(line);
contents.append(newLine);
while ((line = reader.readLine()) != null) {
contents.append(lineTransformer.transform(line + newLine));
}
line = lineTransformer.end();
if (line != null)
contents.append(line);
return contents.toString();
} catch (Exception e) {
throw new RuntimeException(e);
View
@@ -0,0 +1,8 @@
/* Redline Smalltalk, Copyright (c) James C. Ladd. All rights reserved. See LICENSE in the root of this distribution. */
package st.redline.classloader;
public interface LineTransformer {
String transform(String line);
String begin();
String end();
}
View
@@ -0,0 +1,9 @@
/* Redline Smalltalk, Copyright (c) James C. Ladd. All rights reserved. See LICENSE in the root of this distribution. */
package st.redline.classloader;
public class ObjectNotFoundException extends RuntimeException {
public ObjectNotFoundException(String message) {
super(message);
}
}
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -0,0 +1,208 @@
/* Redline Smalltalk, Copyright (c) James C. Ladd. All rights reserved. See LICENSE in the root of this distribution. */
package st.redline.classloader;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/* Note: Move the preprocessing responsibility into an inner class. */
public class SmalltalkSourceFile implements Source, LineTransformer {
public static final String SEPARATOR = "/";
public static final String SOURCE_EXTENSION = ".st";
private static final Pattern METHOD_START_PATTERN = Pattern.compile("^[-+] .*\\s");
private static final Pattern METHOD_UNARY_PATTERN = Pattern.compile("^\\w+[^:|\\s]");
private static final Pattern METHOD_BINARY_PATTERN = Pattern.compile("^[-\\\\+*/=><,@%~|&?]+ \\w+");
private static final Pattern METHOD_KEYWORD_PATTERN = Pattern.compile("(\\w+: \\w+)+");
private static final String METHOD_START = "[";
private static final String METHOD_END = "].";
private static final String CLASS_SELECTOR = "class";
private static final String METHOD_AT_SELECTOR = "basicAddSelector:";
private static final String METHOD_PUT_SELECTOR = "withMethod:";
private static final String CLASS_METHOD_INDICATOR = "+ ";
private static final String NEWLINE = System.getProperty("line.separator");
private final String name;
private final String filename;
private final File file;
private final String classpath;
private final SourceReader reader;
private boolean methods;
protected String className;
protected String selector;
protected String arguments;
protected String fullClassName;
protected String packageName;
public SmalltalkSourceFile(String name, String filename, File file, String classpath, SourceReader reader) {
this.name = name;
this.filename = filename;
this.file = file;
this.classpath = classpath;
this.reader = reader;
this.methods = false;
}
public boolean exists() {
return true;
}
public boolean hasContent() {
return file.length() > 0;
}
public String contents() {
return reader.contents(this);
}
public String transform(String line) {
if (isMethodDefinition(line))
return methodDefinitionTransformation(line);
return line;
}
public String fileExtension() {
return SOURCE_EXTENSION;
}
private String methodDefinitionTransformation(String line) {
StringBuffer transformation = new StringBuffer();
if (hasMethods())
transformation.append(METHOD_END + " ");
transformation.append(className());
if (isClassMethod(line))
transformation.append(" " + CLASS_SELECTOR);
transformation.append(" " + METHOD_AT_SELECTOR);
extractSelectorAndArgumentsFrom(line);
transformation.append(" #" + selector());
transformation.append(" " + METHOD_PUT_SELECTOR);
transformation.append(" " + METHOD_START);
if (arguments.length() > 0)
transformation.append(arguments + " |");
transformation.append(NEWLINE);
methods = true;
return transformation.toString();
}
private String selector() {
return selector;
}
private void extractSelectorAndArgumentsFrom(String line) {
String input = line;
if (input.startsWith("+ ") || input.startsWith("- "))
input = input.substring(2);
arguments = "";
if (!isKeywordSelector(input) && !isUnarySelector(input) && !isBinarySelector(input))
selector = "UnknownSelector";
}
private boolean isUnarySelector(String input) {
Matcher matcher = METHOD_UNARY_PATTERN.matcher(input);
if (matcher.find()) {
selector = matcher.group();
return true;
}
return false;
}
private boolean isBinarySelector(String input) {
Matcher matcher = METHOD_BINARY_PATTERN.matcher(input);
if (matcher.find()) {
selector = matcher.group();
int space = selector.indexOf(' ');
arguments = " :" + selector.substring(space + 1);
selector = selector.substring(0, space);
return true;
}
return false;
}
private boolean isKeywordSelector(String input) {
Matcher matcher = METHOD_KEYWORD_PATTERN.matcher(input);
selector = "";
arguments = "";
boolean found = false;
while (matcher.find()) {
String keyword = matcher.group();
int space = keyword.indexOf(' ');
arguments = arguments + " :" + keyword.substring(space + 1);
selector = selector + keyword.substring(0, space);
found = true;
}
return found;
}
private boolean isClassMethod(String line) {
return line.startsWith(CLASS_METHOD_INDICATOR);
}
public String classpath() {
return classpath;
}
public String name() {
return name;
}
public String className() {
return name();
}
public String fullClassName() {
if (fullClassName == null)
fullClassName = withoutClassPath(withoutExtension(filename()));
return fullClassName;
}
public String packageName() {
if (packageName == null) {
packageName = fullClassName();
int index = packageName.lastIndexOf(File.separatorChar);
if (index != -1)
packageName = packageName.substring(0, index);
packageName = packageName.replaceAll(String.valueOf(File.separatorChar), ".");
}
return packageName;
}
private String withoutClassPath(String filename) {
if (classpath.length() > 0 && filename.startsWith(classpath))
return filename.substring(classpath.length() + 1);
return filename;
}
protected String withoutExtension(String filename) {
return filename.substring(0, filename.lastIndexOf("."));
}
private boolean isMethodDefinition(String line) {
return METHOD_START_PATTERN.matcher(line).matches();
}
public String filename() {
return filename;
}
public String fullFilename() {
return file.getPath();
}
public String begin() {
return "";
}
public String end() {
return hasMethods() ? METHOD_END + NEWLINE : "";
}
private String classInitializer() {
return className() + " initialize." + NEWLINE;
}
private boolean hasMethods() {
return methods;
}
}
View
@@ -0,0 +1,146 @@
/* Redline Smalltalk, Copyright (c) James C. Ladd. All rights reserved. See LICENSE in the root of this distribution. */
package st.redline.classloader;
import java.io.*;
import java.util.*;
import java.util.jar.*;
import static st.redline.classloader.SmalltalkSourceFile.*;
public class SmalltalkSourceFinder implements SourceFinder {
private final SourceFactory sourceFactory;
private final String[] classPaths;
public SmalltalkSourceFinder(SourceFactory sourceFactory, String[] classPaths) {
this.sourceFactory = sourceFactory;
this.classPaths = classPaths;
}
public Source find(String name) {
//System.out.println(">>> find: " + name);
String filename = toFilename(name);
File file = new File(filename);
if (file.exists())
return sourceFile(filename, file, "");
return new SourceNotFound(name);
}
public List<Source> findIn(String packageName) {
//System.out.println("** findIn: " + packageName);
return findInPath(packageName);
}
private List<Source> findInPath(String path) {
String packagePath = path.replace(".", SEPARATOR);
List<Source> sources = new ArrayList<>();
for (String classPath : classPaths)
sources.addAll(findInPath(packagePath, classPath));
return sources;
}
public List<Source> findInPath(String packagePath, String classPath) {
if (isJar(classPath)) {
return findSourceInInJar(packagePath, classPath);
} else
return findSourceInFile(packagePath, classPath);
}
@SuppressWarnings("unchecked")
private List<Source> findSourceInFile(String packagePath, String classPath) {
File folder = new File(classPath + SEPARATOR + packagePath);
if (!folder.isDirectory())
return Collections.EMPTY_LIST;
List<Source> sources = new ArrayList<>();
File[] files = folder.listFiles();
if (files != null)
for (File file : files)
if (file.isFile() && file.getName().endsWith(SOURCE_EXTENSION))
sources.add(sourceFile(packagePath + SEPARATOR + file.getName(), file, classPath));
return sources;
}
private List<Source> findSourceInInJar(String packagePath, String classPath) {
List<Source> sources = new ArrayList<>();
JarFile jarFile = tryCreateJarFile(classPath);
for (Enumeration em1 = jarFile.entries(); em1.hasMoreElements();) {
String entry = em1.nextElement().toString();
int lastSlash = entry.lastIndexOf('/');
int pathLength = packagePath.length();
if (entry.startsWith(packagePath) && pathLength == lastSlash && entry.endsWith(".st"))
sources.add(sourceFactory.createFromJar(entry, classPath));
}
return sources;
}
private JarFile tryCreateJarFile(String classPath) {
try {
return createJarFile(classPath);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public JarFile createJarFile(String classPath) throws IOException {
return new JarFile(classPath);
}
private boolean isJar(String classPath) {
return classPath.endsWith(".jar") || classPath.endsWith(".JAR");
}
private Source sourceFile(String filename, File file, String classpath) {
return sourceFactory.createFromFile(filename, file, classpath);
}
private String toFilename(String name) {
return name.replaceAll("\\.", File.separator) + SOURCE_EXTENSION;
}
public class SourceNotFound implements Source {
private final String name;
public SourceNotFound(String name) {
this.name = name;
}
public boolean exists() {
return false;
}
public boolean hasContent() {
return false;
}
public String contents() {
return "";
}
public String className() {
int index = name.lastIndexOf(".");
if (index == -1)
return name;
return name.substring(index + 1);
}
public String fullClassName() {
return name;
}
public String fileExtension() {
return "";
}
public String packageName() {
int index = name.lastIndexOf(".");
if (index == -1)
return "";
return name.substring(0, index);
}
public String classpath() {
return "";
}
}
}
View
@@ -1,72 +1,14 @@
/* Redline Smalltalk, Copyright (c) James C. Ladd. All rights reserved. See LICENSE in the root of this distribution. */
package st.redline.classloader;
import st.redline.RedlineFile;
import st.redline.classloader.io.SourceReader;
import java.io.File;
public class Source {
private final String name;
private final String path;
private final SourceReader reader;
private final String className;
private final String packageName;
public Source(String name, String path, SourceReader reader) {
this.name = name;
this.path = path;
this.reader = reader;
this.className = makeClassName();
this.packageName = makePackageName();
}
private String makePackageName() {
int index = name.lastIndexOf(RedlineFile.separator);
if (index == -1)
return "";
return name.substring(0, index);
}
private String makeClassName() {
int index = name.lastIndexOf(RedlineFile.separator);
if (index == -1)
index = 0;
return name.substring(index + 1, name.lastIndexOf(".st"));
}
public String name() {
return name;
}
public String path() {
return path;
}
public String className() {
return className;
}
public String packageName() {
return packageName;
}
public String fullyQualifiedName() {
return packageName.replace(RedlineFile.separator, ".") + "." + className;
}
public SourceReader reader() {
return reader;
}
public String contents() {
return reader().contents();
}
public boolean isNextTo(String otherFile) {
String filename = path + RedlineFile.separator + name.replace(className + ".st", otherFile + ".st");
File file = new File(filename);
return file.exists();
}
public interface Source {
boolean hasContent();
boolean exists();
String contents();
String className();
String fullClassName();
String fileExtension();
String packageName();
String classpath();
}
View
@@ -1,30 +1,39 @@
/* Redline Smalltalk, Copyright (c) James C. Ladd. All rights reserved. See LICENSE in the root of this distribution. */
package st.redline.classloader;
import st.redline.RedlineFile;
import st.redline.classloader.io.FileSourceReader;
import st.redline.classloader.io.JarSourceReader;
import st.redline.classloader.io.SourceReader;
import java.io.*;
import static st.redline.classloader.SmalltalkSourceFile.SOURCE_EXTENSION;
public class SourceFactory {
public Source createFromFile(String sourceName, String filePath) {
SourceReader sourceReader = fileSourceReader(sourceName, filePath);
return createSource(sourceName, filePath, sourceReader);
public Source createFromFile(String sourceName, File file, String classpath) {
SourceReader sourceReader = fileSourceReader(file);
return new SmalltalkSourceFile(nameWithoutExtension(file.getName()), sourceName, file, classpath, sourceReader);
}
public Source createFromJar(String sourceName, String jarPath) {
SourceReader sourceReader = jarSourceReader(sourceName, jarPath);
return createSource(sourceName, jarPath, sourceReader);
return new SmalltalkSourceFile(nameWithoutExtensionAndPackage(sourceName), sourceName, new File(jarPath), jarPath, sourceReader);
}
private String nameWithoutExtensionAndPackage(String sourceName) {
String name = nameWithoutExtension(sourceName);
int index = name.lastIndexOf(File.separator);
if (index == -1)
return name;
return name.substring(index + 1);
}
private Source createSource(String name, String path, SourceReader reader) {
return new Source(name, path, reader);
private String nameWithoutExtension(String name) {
int index = name.lastIndexOf(SOURCE_EXTENSION);
if (index == -1)
return name;
return name.substring(0, index);
}
private SourceReader fileSourceReader(String sourceName, String filePath) {
String filename = filePath + RedlineFile.separator + sourceName;
return new FileSourceReader(filename);
private SourceReader fileSourceReader(File file) {
return new FileSourceReader(file);
}
private SourceReader jarSourceReader(String entryName, String jarPath) {
View
@@ -1,128 +1,10 @@
/* Redline Smalltalk, Copyright (c) James C. Ladd. All rights reserved. See LICENSE in the root of this distribution. */
package st.redline.classloader;
import st.redline.RedlineFile;
import java.util.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
public interface SourceFinder {
public class SourceFinder {
public static final String WINDOWS_PATH_SEPARATOR = "\\";
public static final String JAR_PATH_SEPARATOR = "/";
private static final String SOURCE_EXTENSION = ".st";
private SourceFactory sourceFactory;
private final String[] classPaths;
public SourceFinder(SourceFactory sourceFactory, String[] classPaths) {
this.sourceFactory = sourceFactory;
this.classPaths = classPaths;
}
public List<Source> findIn(String path) {
String packagePath = path.replace(".", RedlineFile.separator);
List<Source> sources = new ArrayList<Source>();
for (String classPath : classPaths)
sources.addAll(findIn(packagePath, classPath));
return sources;
}
public List<Source> findIn(String packagePath, String classPath) {
if (isJar(classPath))
return findSourceInInJar(packagePath, classPath);
else
return findSourceInFile(packagePath, classPath);
}
private List<Source> findSourceInInJar(String packagePath, String classPath) {
List<Source> sources = new ArrayList<Source>();
JarFile jarFile = tryCreateJarFile(classPath);
for (Enumeration em1 = jarFile.entries(); em1.hasMoreElements();) {
String entry = em1.nextElement().toString();
int lastSlash = entry.lastIndexOf('/');
int pathLength = packagePath.length();
if (entry.startsWith(packagePath) && pathLength == lastSlash && entry.endsWith(".st"))
sources.add(sourceFactory.createFromJar(entry, classPath));
}
return sources;
}
private List<Source> findSourceInFile(String packagePath, String classPath) {
File folder = new File(classPath + RedlineFile.separator + packagePath);
if (!folder.isDirectory())
return Collections.EMPTY_LIST;
List<Source> sources = new ArrayList<Source>();
for (File file : folder.listFiles())
if (file.isFile() && file.getName().endsWith(".st"))
sources.add(sourceFactory.createFromFile(packagePath + RedlineFile.separator + file.getName(), file.getAbsolutePath()));
return sources;
}
public Source find(String name) {
String sourceName = makeFilename(name);
return findSource(sourceName);
}
public Source findSource(String sourceName) {
Source source;
for (String classPath : classPaths)
if ((source = findSource(sourceName, classPath)) != null)
return source;
return null;
}
public Source findSource(String sourceName, String classPath) {
if (isJar(classPath))
return findSourceInJar(sourceName, classPath);
else
return findSourceFile(sourceName, classPath);
}
private Source findSourceInJar(String sourceName, String classPath) {
JarFile jarFile = tryCreateJarFile(classPath);
String sourceNameForJar = sourceName.replace(WINDOWS_PATH_SEPARATOR, JAR_PATH_SEPARATOR);
ZipEntry entry = jarFile.getEntry(sourceNameForJar);
if (entry != null)
return sourceFactory.createFromJar(sourceNameForJar, classPath);
return null;
}
private JarFile tryCreateJarFile(String classPath) {
try {
return createJarFile(classPath);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private boolean isJar(String classPath) {
return classPath.endsWith(".jar") || classPath.endsWith(".JAR");
}
private Source findSourceFile(String sourceName, String classPath) {
File file = createFile(sourceName, classPath);
if (file.exists())
return sourceFactory.createFromFile(sourceName, classPath);
return null;
}
public File createFile(String sourceName, String classPath) {
return new File(classPath + RedlineFile.separator + sourceName);
}
public JarFile createJarFile(String classPath) throws IOException {
return new JarFile(classPath);
}
private String makeFilename(String name) {
String filename = name.replace(".", RedlineFile.separator);
return filename + SOURCE_EXTENSION;
}
Source find(String name);
List<Source> findIn(String packageName);
}
View
@@ -1,6 +1,7 @@
/* Redline Smalltalk, Copyright (c) James C. Ladd. All rights reserved. See LICENSE in the root of this distribution. */
package st.redline.classloader.io;
package st.redline.classloader;
public interface SourceReader {
String contents();
String contents(LineTransformer lineTransformer);
}
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
Oops, something went wrong.