├── .classpath ├── .project ├── LICENSE ├── README.md ├── gluonj.jar └── src ├── chap10 ├── ArrayEvaluator.java └── ArrayRunner.java ├── chap11 ├── ArrayEnv.java ├── EnvOptInterpreter.java ├── EnvOptRunner.java ├── EnvOptimizer.java ├── OptFunction.java ├── ResizableArrayEnv.java └── Symbols.java ├── chap12 ├── InlineCache.java ├── InlineRunner.java ├── MemberSymbols.java ├── ObjOptInterpreter.java ├── ObjOptRunner.java ├── ObjOptimizer.java ├── OptClassInfo.java ├── OptMethod.java ├── OptStoneObject.java └── SymbolThis.java ├── chap13 ├── Code.java ├── HeapMemory.java ├── Opcode.java ├── StoneVM.java ├── StoneVMEnv.java ├── VmEvaluator.java ├── VmFunction.java ├── VmInterpreter.java └── VmRunner.java ├── chap14 ├── InferFuncTypes.java ├── InferRunner.java ├── InferTypes.java ├── JavaFunction.java ├── JavaLoader.java ├── JavaRunner.java ├── Runtime.java ├── ToJava.java ├── TypeChecker.java ├── TypeEnv.java ├── TypeException.java ├── TypeInfo.java ├── TypedEvaluator.java ├── TypedInterpreter.java ├── TypedNatives.java ├── TypedRunner.java └── java │ ├── currentTime.java │ ├── length.java │ ├── print.java │ ├── read.java │ └── toInt.java ├── chap3 ├── FileLexerRunner.java └── LexerRunner.java ├── chap5 └── ParserRunner.java ├── chap6 ├── BasicEnv.java ├── BasicEvaluator.java ├── BasicFileInterpreter.java ├── BasicInterpreter.java ├── Environment.java ├── FileRunner.java ├── Runner.java └── sum.stone ├── chap7 ├── ClosureEvaluator.java ├── ClosureInterpreter.java ├── ClosureRunner.java ├── FuncEvaluator.java ├── FuncInterpreter.java ├── FuncRunner.java ├── Function.java └── NestedEnv.java ├── chap8 ├── NativeEvaluator.java ├── NativeFunction.java ├── NativeInterpreter.java ├── NativeRunner.java └── Natives.java ├── chap9 ├── ClassEvaluator.java ├── ClassInfo.java ├── ClassInterpreter.java ├── ClassRunner.java └── StoneObject.java ├── chapA └── Lexer.java ├── chapB ├── ExprParser.java └── OpPrecedenceParser.java └── stone ├── ArrayParser.java ├── BasicParser.java ├── ClassParser.java ├── ClosureParser.java ├── CodeDialog.java ├── FuncParser.java ├── Lexer.java ├── ParseException.java ├── Parser.java ├── StoneException.java ├── Token.java ├── TypedParser.java └── ast ├── ASTLeaf.java ├── ASTList.java ├── ASTree.java ├── Arguments.java ├── ArrayLiteral.java ├── ArrayRef.java ├── BinaryExpr.java ├── BlockStmnt.java ├── ClassBody.java ├── ClassStmnt.java ├── DefStmnt.java ├── Dot.java ├── Fun.java ├── IfStmnt.java ├── Name.java ├── NegativeExpr.java ├── NullStmnt.java ├── NumberLiteral.java ├── ParameterList.java ├── Postfix.java ├── PrimaryExpr.java ├── StringLiteral.java ├── TypeTag.java ├── VarStmnt.java └── WhileStmnt.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | stone-lang 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Shigeru Chiba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stone 2 | A simple programming language written for book "A new scripting language in two weeks" (千葉 滋、「2週間でできる!スクリプト言語の作り方」技術評論社、2012, ISBN 978-4-7741-4974-5). 3 | 4 | The source of gluonj.jar is available from https://github.com/chibash/gluonj 5 | 6 | To compile, 7 | 8 | ``` 9 | javac -d ./bin -sourcepath ./src -cp gluonj.jar src/*/*.java 10 | ``` 11 | 12 | and to run, for example, 13 | 14 | ``` 15 | java -cp ./bin:gluonj.jar chap6/Runner 16 | ``` 17 | -------------------------------------------------------------------------------- /gluonj.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chibash/stone/06a12b7e812fb38ebebc21c8add4cdf82af45b6a/gluonj.jar -------------------------------------------------------------------------------- /src/chap10/ArrayEvaluator.java: -------------------------------------------------------------------------------- 1 | package chap10; 2 | import java.util.List; 3 | import javassist.gluonj.*; 4 | import stone.ArrayParser; 5 | import stone.StoneException; 6 | import stone.ast.*; 7 | import chap6.Environment; 8 | import chap6.BasicEvaluator; 9 | import chap6.BasicEvaluator.ASTreeEx; 10 | import chap7.FuncEvaluator; 11 | import chap7.FuncEvaluator.PrimaryEx; 12 | 13 | @Require({FuncEvaluator.class, ArrayParser.class}) 14 | @Reviser public class ArrayEvaluator { 15 | @Reviser public static class ArrayLitEx extends ArrayLiteral { 16 | public ArrayLitEx(List list) { super(list); } 17 | public Object eval(Environment env) { 18 | int s = numChildren(); 19 | Object[] res = new Object[s]; 20 | int i = 0; 21 | for (ASTree t: this) 22 | res[i++] = ((ASTreeEx)t).eval(env); 23 | return res; 24 | } 25 | } 26 | @Reviser public static class ArrayRefEx extends ArrayRef { 27 | public ArrayRefEx(List c) { super(c); } 28 | public Object eval(Environment env, Object value) { 29 | if (value instanceof Object[]) { 30 | Object index = ((ASTreeEx)index()).eval(env); 31 | if (index instanceof Integer) 32 | return ((Object[])value)[(Integer)index]; 33 | } 34 | 35 | throw new StoneException("bad array access", this); 36 | } 37 | } 38 | @Reviser public static class AssignEx extends BasicEvaluator.BinaryEx { 39 | public AssignEx(List c) { super(c); } 40 | @Override 41 | protected Object computeAssign(Environment env, Object rvalue) { 42 | ASTree le = left(); 43 | if (le instanceof PrimaryExpr) { 44 | PrimaryEx p = (PrimaryEx)le; 45 | if (p.hasPostfix(0) && p.postfix(0) instanceof ArrayRef) { 46 | Object a = ((PrimaryEx)le).evalSubExpr(env, 1); 47 | if (a instanceof Object[]) { 48 | ArrayRef aref = (ArrayRef)p.postfix(0); 49 | Object index = ((ASTreeEx)aref.index()).eval(env); 50 | if (index instanceof Integer) { 51 | ((Object[])a)[(Integer)index] = rvalue; 52 | return rvalue; 53 | } 54 | } 55 | throw new StoneException("bad array access", this); 56 | } 57 | } 58 | return super.computeAssign(env, rvalue); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/chap10/ArrayRunner.java: -------------------------------------------------------------------------------- 1 | package chap10; 2 | import javassist.gluonj.util.Loader; 3 | import chap7.ClosureEvaluator; 4 | import chap8.NativeEvaluator; 5 | import chap9.ClassEvaluator; 6 | import chap9.ClassInterpreter; 7 | 8 | public class ArrayRunner { 9 | public static void main(String[] args) throws Throwable { 10 | Loader.run(ClassInterpreter.class, args, ClassEvaluator.class, 11 | ArrayEvaluator.class, NativeEvaluator.class, 12 | ClosureEvaluator.class); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/chap11/ArrayEnv.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | import stone.StoneException; 3 | import chap11.EnvOptimizer.EnvEx2; 4 | import chap6.Environment; 5 | 6 | public class ArrayEnv implements Environment { 7 | protected Object[] values; 8 | protected Environment outer; 9 | public ArrayEnv(int size, Environment out) { 10 | values = new Object[size]; 11 | outer = out; 12 | } 13 | public Symbols symbols() { throw new StoneException("no symbols"); } 14 | public Object get(int nest, int index) { 15 | if (nest == 0) 16 | return values[index]; 17 | else if (outer == null) 18 | return null; 19 | else 20 | return ((EnvEx2)outer).get(nest - 1, index); 21 | } 22 | public void put(int nest, int index, Object value) { 23 | if (nest == 0) 24 | values[index] = value; 25 | else if (outer == null) 26 | throw new StoneException("no outer environment"); 27 | else 28 | ((EnvEx2)outer).put(nest - 1, index, value); 29 | } 30 | public Object get(String name) { error(name); return null; } 31 | public void put(String name, Object value) { error(name); } 32 | public void putNew(String name, Object value) { error(name); } 33 | public Environment where(String name) { error(name); return null; } 34 | public void setOuter(Environment e) { outer = e; } 35 | private void error(String name) { 36 | throw new StoneException("cannot access by name: " + name); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/chap11/EnvOptInterpreter.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | import chap6.BasicEvaluator; 3 | import chap6.Environment; 4 | import chap8.Natives; 5 | import stone.BasicParser; 6 | import stone.ClosureParser; 7 | import stone.CodeDialog; 8 | import stone.Lexer; 9 | import stone.ParseException; 10 | import stone.Token; 11 | import stone.ast.ASTree; 12 | import stone.ast.NullStmnt; 13 | 14 | public class EnvOptInterpreter { 15 | public static void main(String[] args) throws ParseException { 16 | run(new ClosureParser(), 17 | new Natives().environment(new ResizableArrayEnv())); 18 | } 19 | public static void run(BasicParser bp, Environment env) 20 | throws ParseException 21 | { 22 | Lexer lexer = new Lexer(new CodeDialog()); 23 | while (lexer.peek(0) != Token.EOF) { 24 | ASTree t = bp.parse(lexer); 25 | if (!(t instanceof NullStmnt)) { 26 | ((EnvOptimizer.ASTreeOptEx)t).lookup( 27 | ((EnvOptimizer.EnvEx2)env).symbols()); 28 | Object r = ((BasicEvaluator.ASTreeEx)t).eval(env); 29 | System.out.println("=> " + r); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/chap11/EnvOptRunner.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | import chap8.NativeEvaluator; 3 | import javassist.gluonj.util.Loader; 4 | 5 | public class EnvOptRunner { 6 | public static void main(String[] args) throws Throwable { 7 | Loader.run(EnvOptInterpreter.class, args, EnvOptimizer.class, 8 | NativeEvaluator.class); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/chap11/EnvOptimizer.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | import static javassist.gluonj.GluonJ.revise; 3 | import javassist.gluonj.*; 4 | import java.util.List; 5 | import stone.Token; 6 | import stone.StoneException; 7 | import stone.ast.*; 8 | import chap11.Symbols.Location; 9 | import chap6.Environment; 10 | import chap6.BasicEvaluator; 11 | import chap7.ClosureEvaluator; 12 | 13 | @Require(ClosureEvaluator.class) 14 | @Reviser public class EnvOptimizer { 15 | @Reviser public static interface EnvEx2 extends Environment { 16 | Symbols symbols(); 17 | void put(int nest, int index, Object value); 18 | Object get(int nest, int index); 19 | void putNew(String name, Object value); 20 | Environment where(String name); 21 | } 22 | @Reviser public static abstract class ASTreeOptEx extends ASTree { 23 | public void lookup(Symbols syms) {} 24 | } 25 | @Reviser public static class ASTListEx extends ASTList { 26 | public ASTListEx(List c) { super(c); } 27 | public void lookup(Symbols syms) { 28 | for (ASTree t: this) 29 | ((ASTreeOptEx)t).lookup(syms); 30 | } 31 | } 32 | @Reviser public static class DefStmntEx extends DefStmnt { 33 | protected int index, size; 34 | public DefStmntEx(List c) { super(c); } 35 | public void lookup(Symbols syms) { 36 | index = syms.putNew(name()); 37 | size = FunEx.lookup(syms, parameters(), body()); 38 | } 39 | public Object eval(Environment env) { 40 | ((EnvEx2)env).put(0, index, new OptFunction(parameters(), body(), 41 | env, size)); 42 | return name(); 43 | } 44 | } 45 | @Reviser public static class FunEx extends Fun { 46 | protected int size = -1; 47 | public FunEx(List c) { super(c); } 48 | public void lookup(Symbols syms) { 49 | size = lookup(syms, parameters(), body()); 50 | } 51 | public Object eval(Environment env) { 52 | return new OptFunction(parameters(), body(), env, size); 53 | } 54 | public static int lookup(Symbols syms, ParameterList params, 55 | BlockStmnt body) 56 | { 57 | Symbols newSyms = new Symbols(syms); 58 | ((ParamsEx)params).lookup(newSyms); 59 | ((ASTreeOptEx)revise(body)).lookup(newSyms); 60 | return newSyms.size(); 61 | } 62 | } 63 | @Reviser public static class ParamsEx extends ParameterList { 64 | protected int[] offsets = null; 65 | public ParamsEx(List c) { super(c); } 66 | public void lookup(Symbols syms) { 67 | int s = size(); 68 | offsets = new int[s]; 69 | for (int i = 0; i < s; i++) 70 | offsets[i] = syms.putNew(name(i)); 71 | } 72 | public void eval(Environment env, int index, Object value) { 73 | ((EnvEx2)env).put(0, offsets[index], value); 74 | } 75 | } 76 | @Reviser public static class NameEx extends Name { 77 | protected static final int UNKNOWN = -1; 78 | protected int nest, index; 79 | public NameEx(Token t) { super(t); index = UNKNOWN; } 80 | public void lookup(Symbols syms) { 81 | Location loc = syms.get(name()); 82 | if (loc == null) 83 | throw new StoneException("undefined name: " + name(), this); 84 | else { 85 | nest = loc.nest; 86 | index = loc.index; 87 | } 88 | } 89 | public void lookupForAssign(Symbols syms) { 90 | Location loc = syms.put(name()); 91 | nest = loc.nest; 92 | index = loc.index; 93 | } 94 | public Object eval(Environment env) { 95 | if (index == UNKNOWN) 96 | return env.get(name()); 97 | else 98 | return ((EnvEx2)env).get(nest, index); 99 | } 100 | public void evalForAssign(Environment env, Object value) { 101 | if (index == UNKNOWN) 102 | env.put(name(), value); 103 | else 104 | ((EnvEx2)env).put(nest, index, value); 105 | } 106 | } 107 | @Reviser public static class BinaryEx2 extends BasicEvaluator.BinaryEx { 108 | public BinaryEx2(List c) { super(c); } 109 | public void lookup(Symbols syms) { 110 | ASTree left = left(); 111 | if ("=".equals(operator())) { 112 | if (left instanceof Name) { 113 | ((NameEx)left).lookupForAssign(syms); 114 | ((ASTreeOptEx)right()).lookup(syms); 115 | return; 116 | } 117 | } 118 | ((ASTreeOptEx)left).lookup(syms); 119 | ((ASTreeOptEx)right()).lookup(syms); 120 | } 121 | @Override 122 | protected Object computeAssign(Environment env, Object rvalue) { 123 | ASTree l = left(); 124 | if (l instanceof Name) { 125 | ((NameEx)l).evalForAssign(env, rvalue); 126 | return rvalue; 127 | } 128 | else 129 | return super.computeAssign(env, rvalue); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/chap11/OptFunction.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | import stone.ast.BlockStmnt; 3 | import stone.ast.ParameterList; 4 | import chap6.Environment; 5 | import chap7.Function; 6 | 7 | public class OptFunction extends Function { 8 | protected int size; 9 | public OptFunction(ParameterList parameters, BlockStmnt body, 10 | Environment env, int memorySize) 11 | { 12 | super(parameters, body, env); 13 | size = memorySize; 14 | } 15 | @Override public Environment makeEnv() { return new ArrayEnv(size, env); } 16 | } 17 | -------------------------------------------------------------------------------- /src/chap11/ResizableArrayEnv.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | import java.util.Arrays; 3 | import chap6.Environment; 4 | import chap11.EnvOptimizer.EnvEx2; 5 | 6 | public class ResizableArrayEnv extends ArrayEnv { 7 | protected Symbols names; 8 | public ResizableArrayEnv() { 9 | super(10, null); 10 | names = new Symbols(); 11 | } 12 | @Override public Symbols symbols() { return names; } 13 | @Override public Object get(String name) { 14 | Integer i = names.find(name); 15 | if (i == null) 16 | if (outer == null) 17 | return null; 18 | else 19 | return outer.get(name); 20 | else 21 | return values[i]; 22 | } 23 | @Override public void put(String name, Object value) { 24 | Environment e = where(name); 25 | if (e == null) 26 | e = this; 27 | ((EnvEx2)e).putNew(name, value); 28 | } 29 | @Override public void putNew(String name, Object value) { 30 | assign(names.putNew(name), value); 31 | } 32 | @Override public Environment where(String name) { 33 | if (names.find(name) != null) 34 | return this; 35 | else if (outer == null) 36 | return null; 37 | else 38 | return ((EnvEx2)outer).where(name); 39 | } 40 | @Override public void put(int nest, int index, Object value) { 41 | if (nest == 0) 42 | assign(index, value); 43 | else 44 | super.put(nest, index, value); 45 | } 46 | protected void assign(int index, Object value) { 47 | if (index >= values.length) { 48 | int newLen = values.length * 2; 49 | if (index >= newLen) 50 | newLen = index + 1; 51 | values = Arrays.copyOf(values, newLen); 52 | } 53 | values[index] = value; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/chap11/Symbols.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | import java.util.HashMap; 3 | 4 | public class Symbols { 5 | public static class Location { 6 | public int nest, index; 7 | public Location(int nest, int index) { 8 | this.nest = nest; 9 | this.index = index; 10 | } 11 | } 12 | protected Symbols outer; 13 | protected HashMap table; 14 | public Symbols() { this(null); } 15 | public Symbols(Symbols outer) { 16 | this.outer = outer; 17 | this.table = new HashMap(); 18 | } 19 | public int size() { return table.size(); } 20 | public void append(Symbols s) { table.putAll(s.table); } 21 | public Integer find(String key) { return table.get(key); } 22 | public Location get(String key) { return get(key, 0); } 23 | public Location get(String key, int nest) { 24 | Integer index = table.get(key); 25 | if (index == null) 26 | if (outer == null) 27 | return null; 28 | else 29 | return outer.get(key, nest + 1); 30 | else 31 | return new Location(nest, index.intValue()); 32 | } 33 | public int putNew(String key) { 34 | Integer i = find(key); 35 | if (i == null) 36 | return add(key); 37 | else 38 | return i; 39 | } 40 | public Location put(String key) { 41 | Location loc = get(key, 0); 42 | if (loc == null) 43 | return new Location(0, add(key)); 44 | else 45 | return loc; 46 | } 47 | protected int add(String key) { 48 | int i = table.size(); 49 | table.put(key, i); 50 | return i; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/chap12/InlineCache.java: -------------------------------------------------------------------------------- 1 | package chap12; 2 | import java.util.List; 3 | import stone.StoneException; 4 | import stone.ast.ASTree; 5 | import stone.ast.Dot; 6 | import chap6.Environment; 7 | import javassist.gluonj.*; 8 | 9 | @Require(ObjOptimizer.class) 10 | @Reviser public class InlineCache { 11 | @Reviser public static class DotEx2 extends ObjOptimizer.DotEx { 12 | protected OptClassInfo classInfo = null; 13 | protected boolean isField; 14 | protected int index; 15 | public DotEx2(List c) { super(c); } 16 | @Override public Object eval(Environment env, Object value) { 17 | if (value instanceof OptStoneObject) { 18 | OptStoneObject target = (OptStoneObject)value; 19 | if (target.classInfo() != classInfo) 20 | updateCache(target); 21 | if (isField) 22 | return target.read(index); 23 | else 24 | return target.method(index); 25 | } 26 | else 27 | return super.eval(env, value); 28 | } 29 | protected void updateCache(OptStoneObject target) { 30 | String member = name(); 31 | classInfo = target.classInfo(); 32 | Integer i = classInfo.fieldIndex(member); 33 | if (i != null) { 34 | isField = true; 35 | index = i; 36 | return; 37 | } 38 | i = classInfo.methodIndex(member); 39 | if (i != null) { 40 | isField = false; 41 | index = i; 42 | return; 43 | } 44 | throw new StoneException("bad member access: " + member, this); 45 | } 46 | } 47 | @Reviser public static class AssignEx2 extends ObjOptimizer.AssignEx { 48 | protected OptClassInfo classInfo = null; 49 | protected int index; 50 | public AssignEx2(List c) { super(c); } 51 | @Override protected Object setField(OptStoneObject obj, Dot expr, 52 | Object rvalue) 53 | { 54 | if (obj.classInfo() != classInfo) { 55 | String member = expr.name(); 56 | classInfo = obj.classInfo(); 57 | Integer i = classInfo.fieldIndex(member); 58 | if (i == null) 59 | throw new StoneException("bad member access: " + member, 60 | this); 61 | index = i; 62 | } 63 | obj.write(index, rvalue); 64 | return rvalue; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/chap12/InlineRunner.java: -------------------------------------------------------------------------------- 1 | package chap12; 2 | import javassist.gluonj.util.Loader; 3 | import chap8.NativeEvaluator; 4 | 5 | public class InlineRunner { 6 | public static void main(String[] args) throws Throwable { 7 | Loader.run(ObjOptInterpreter.class, args, InlineCache.class, 8 | NativeEvaluator.class); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/chap12/MemberSymbols.java: -------------------------------------------------------------------------------- 1 | package chap12; 2 | import chap11.Symbols; 3 | 4 | public class MemberSymbols extends Symbols { 5 | public static int METHOD = -1; 6 | public static int FIELD = -2; 7 | protected int type; 8 | public MemberSymbols(Symbols outer, int type) { 9 | super(outer); 10 | this.type = type; 11 | } 12 | @Override public Location get(String key, int nest) { 13 | Integer index = table.get(key); 14 | if (index == null) 15 | if (outer == null) 16 | return null; 17 | else 18 | return outer.get(key, nest); 19 | else 20 | return new Location(type, index.intValue()); 21 | } 22 | @Override public Location put(String key) { 23 | Location loc = get(key, 0); 24 | if (loc == null) 25 | return new Location(type, add(key)); 26 | else 27 | return loc; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/chap12/ObjOptInterpreter.java: -------------------------------------------------------------------------------- 1 | package chap12; 2 | import stone.ClassParser; 3 | import stone.ParseException; 4 | import chap11.EnvOptInterpreter; 5 | import chap11.ResizableArrayEnv; 6 | import chap8.Natives; 7 | 8 | public class ObjOptInterpreter extends EnvOptInterpreter { 9 | public static void main(String[] args) throws ParseException { 10 | run(new ClassParser(), 11 | new Natives().environment(new ResizableArrayEnv())); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/chap12/ObjOptRunner.java: -------------------------------------------------------------------------------- 1 | package chap12; 2 | import javassist.gluonj.util.Loader; 3 | import chap8.NativeEvaluator; 4 | 5 | public class ObjOptRunner { 6 | public static void main(String[] args) throws Throwable { 7 | Loader.run(ObjOptInterpreter.class, args, ObjOptimizer.class, 8 | NativeEvaluator.class); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/chap12/ObjOptimizer.java: -------------------------------------------------------------------------------- 1 | package chap12; 2 | import java.util.ArrayList; 3 | import java.util.List; 4 | import static javassist.gluonj.GluonJ.revise; 5 | import javassist.gluonj.*; 6 | import stone.*; 7 | import stone.ast.*; 8 | import chap6.Environment; 9 | import chap6.BasicEvaluator; 10 | import chap6.BasicEvaluator.ASTreeEx; 11 | import chap7.FuncEvaluator.PrimaryEx; 12 | import chap11.ArrayEnv; 13 | import chap11.EnvOptimizer; 14 | import chap11.Symbols; 15 | import chap11.EnvOptimizer.ASTreeOptEx; 16 | import chap11.EnvOptimizer.EnvEx2; 17 | import chap11.EnvOptimizer.ParamsEx; 18 | import chap12.OptStoneObject.AccessException; 19 | 20 | @Require(EnvOptimizer.class) 21 | @Reviser public class ObjOptimizer { 22 | @Reviser public static class ClassStmntEx extends ClassStmnt { 23 | public ClassStmntEx(List c) { super(c); } 24 | public void lookup(Symbols syms) {} 25 | public Object eval(Environment env) { 26 | Symbols methodNames = new MemberSymbols(((EnvEx2)env).symbols(), 27 | MemberSymbols.METHOD); 28 | Symbols fieldNames = new MemberSymbols(methodNames, 29 | MemberSymbols.FIELD); 30 | OptClassInfo ci = new OptClassInfo(this, env, methodNames, 31 | fieldNames); 32 | ((EnvEx2)env).put(name(), ci); 33 | ArrayList methods = new ArrayList(); 34 | if (ci.superClass() != null) 35 | ci.superClass().copyTo(fieldNames, methodNames, methods); 36 | Symbols newSyms = new SymbolThis(fieldNames); 37 | ((ClassBodyEx)body()).lookup(newSyms, methodNames, fieldNames, 38 | methods); 39 | ci.setMethods(methods); 40 | return name(); 41 | } 42 | } 43 | @Reviser public static class ClassBodyEx extends ClassBody { 44 | public ClassBodyEx(List c) { super(c); } 45 | public Object eval(Environment env) { 46 | for (ASTree t: this) 47 | if (!(t instanceof DefStmnt)) 48 | ((ASTreeEx)t).eval(env); 49 | return null; 50 | } 51 | public void lookup(Symbols syms, Symbols methodNames, 52 | Symbols fieldNames, ArrayList methods) 53 | { 54 | for (ASTree t: this) { 55 | if (t instanceof DefStmnt) { 56 | DefStmnt def = (DefStmnt)t; 57 | int oldSize = methodNames.size(); 58 | int i = methodNames.putNew(def.name()); 59 | if (i >= oldSize) 60 | methods.add(def); 61 | else 62 | methods.set(i, def); 63 | ((DefStmntEx2)def).lookupAsMethod(fieldNames); 64 | } 65 | else 66 | ((ASTreeOptEx)t).lookup(syms); 67 | } 68 | } 69 | } 70 | @Reviser public static class DefStmntEx2 extends EnvOptimizer.DefStmntEx { 71 | public DefStmntEx2(List c) { super(c); } 72 | public int locals() { return size; } 73 | public void lookupAsMethod(Symbols syms) { 74 | Symbols newSyms = new Symbols(syms); 75 | newSyms.putNew(SymbolThis.NAME); 76 | ((ParamsEx)parameters()).lookup(newSyms); 77 | ((ASTreeOptEx)revise(body())).lookup(newSyms); 78 | size = newSyms.size(); 79 | } 80 | } 81 | @Reviser public static class DotEx extends Dot { 82 | public DotEx(List c) { super(c); } 83 | public Object eval(Environment env, Object value) { 84 | String member = name(); 85 | if (value instanceof OptClassInfo) { 86 | if ("new".equals(member)) { 87 | OptClassInfo ci = (OptClassInfo)value; 88 | ArrayEnv newEnv = new ArrayEnv(1, ci.environment()); 89 | OptStoneObject so = new OptStoneObject(ci, ci.size()); 90 | newEnv.put(0, 0, so); 91 | initObject(ci, so, newEnv); 92 | return so; 93 | } 94 | } 95 | else if (value instanceof OptStoneObject) { 96 | try { 97 | return ((OptStoneObject)value).read(member); 98 | } catch (AccessException e) {} 99 | } 100 | throw new StoneException("bad member access: " + member, this); 101 | } 102 | protected void initObject(OptClassInfo ci, OptStoneObject obj, 103 | Environment env) 104 | { 105 | if (ci.superClass() != null) 106 | initObject(ci.superClass(), obj, env); 107 | ((ClassBodyEx)ci.body()).eval(env); 108 | } 109 | } 110 | @Reviser public static class NameEx2 extends EnvOptimizer.NameEx { 111 | public NameEx2(Token t) { super(t); } 112 | @Override public Object eval(Environment env) { 113 | if (index == UNKNOWN) 114 | return env.get(name()); 115 | else if (nest == MemberSymbols.FIELD) 116 | return getThis(env).read(index); 117 | else if (nest == MemberSymbols.METHOD) 118 | return getThis(env).method(index); 119 | else 120 | return ((EnvEx2)env).get(nest, index); 121 | } 122 | @Override public void evalForAssign(Environment env, Object value) { 123 | if (index == UNKNOWN) 124 | env.put(name(), value); 125 | else if (nest == MemberSymbols.FIELD) 126 | getThis(env).write(index, value); 127 | else if (nest == MemberSymbols.METHOD) 128 | throw new StoneException("cannot update a method: " + name(), 129 | this); 130 | else 131 | ((EnvEx2)env).put(nest, index, value); 132 | } 133 | protected OptStoneObject getThis(Environment env) { 134 | return (OptStoneObject)((EnvEx2)env).get(0, 0); 135 | } 136 | } 137 | @Reviser public static class AssignEx extends BasicEvaluator.BinaryEx { 138 | public AssignEx(List c) { super(c); } 139 | @Override 140 | protected Object computeAssign(Environment env, Object rvalue) { 141 | ASTree le = left(); 142 | if (le instanceof PrimaryExpr) { 143 | PrimaryEx p = (PrimaryEx)le; 144 | if (p.hasPostfix(0) && p.postfix(0) instanceof Dot) { 145 | Object t = ((PrimaryEx)le).evalSubExpr(env, 1); 146 | if (t instanceof OptStoneObject) 147 | return setField((OptStoneObject)t, (Dot)p.postfix(0), 148 | rvalue); 149 | } 150 | } 151 | return super.computeAssign(env, rvalue); 152 | } 153 | protected Object setField(OptStoneObject obj, Dot expr, Object rvalue) { 154 | String name = expr.name(); 155 | try { 156 | obj.write(name, rvalue); 157 | return rvalue; 158 | } catch (AccessException e) { 159 | throw new StoneException("bad member access: " + name, this); 160 | } 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/chap12/OptClassInfo.java: -------------------------------------------------------------------------------- 1 | package chap12; 2 | import java.util.ArrayList; 3 | import stone.ast.ClassStmnt; 4 | import stone.ast.DefStmnt; 5 | import chap11.Symbols; 6 | import chap12.ObjOptimizer.DefStmntEx2; 7 | import chap6.Environment; 8 | import chap9.ClassInfo; 9 | 10 | public class OptClassInfo extends ClassInfo { 11 | protected Symbols methods, fields; 12 | protected DefStmnt[] methodDefs; 13 | public OptClassInfo(ClassStmnt cs, Environment env, Symbols methods, 14 | Symbols fields) 15 | { 16 | super(cs, env); 17 | this.methods = methods; 18 | this.fields = fields; 19 | this.methodDefs = null; 20 | } 21 | public int size() { return fields.size(); } 22 | @Override public OptClassInfo superClass() { 23 | return (OptClassInfo)superClass; 24 | } 25 | public void copyTo(Symbols f, Symbols m, ArrayList mlist) { 26 | f.append(fields); 27 | m.append(methods); 28 | for (DefStmnt def: methodDefs) 29 | mlist.add(def); 30 | } 31 | public Integer fieldIndex(String name) { return fields.find(name); } 32 | public Integer methodIndex(String name) { return methods.find(name); } 33 | public Object method(OptStoneObject self, int index) { 34 | DefStmnt def = methodDefs[index]; 35 | return new OptMethod(def.parameters(), def.body(), environment(), 36 | ((DefStmntEx2)def).locals(), self); 37 | } 38 | public void setMethods(ArrayList methods) { 39 | methodDefs = methods.toArray(new DefStmnt[methods.size()]); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/chap12/OptMethod.java: -------------------------------------------------------------------------------- 1 | package chap12; 2 | import stone.ast.BlockStmnt; 3 | import stone.ast.ParameterList; 4 | import chap11.ArrayEnv; 5 | import chap11.OptFunction; 6 | import chap6.Environment; 7 | 8 | public class OptMethod extends OptFunction { 9 | OptStoneObject self; 10 | public OptMethod(ParameterList parameters, BlockStmnt body, 11 | Environment env, int memorySize, OptStoneObject self) 12 | { 13 | super(parameters, body, env, memorySize); 14 | this.self = self; 15 | } 16 | @Override public Environment makeEnv() { 17 | ArrayEnv e = new ArrayEnv(size, env); 18 | e.put(0, 0, self); 19 | return e; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/chap12/OptStoneObject.java: -------------------------------------------------------------------------------- 1 | package chap12; 2 | 3 | public class OptStoneObject { 4 | public static class AccessException extends Exception {} 5 | protected OptClassInfo classInfo; 6 | protected Object[] fields; 7 | public OptStoneObject(OptClassInfo ci, int size) { 8 | classInfo = ci; 9 | fields = new Object[size]; 10 | } 11 | public OptClassInfo classInfo() { return classInfo; } 12 | public Object read(String name) throws AccessException { 13 | Integer i = classInfo.fieldIndex(name); 14 | if (i != null) 15 | return fields[i]; 16 | else { 17 | i = classInfo.methodIndex(name); 18 | if (i != null) 19 | return method(i); 20 | } 21 | throw new AccessException(); 22 | } 23 | public void write(String name, Object value) throws AccessException { 24 | Integer i = classInfo.fieldIndex(name); 25 | if (i == null) 26 | throw new AccessException(); 27 | else 28 | fields[i] = value; 29 | } 30 | public Object read(int index) { 31 | return fields[index]; 32 | } 33 | public void write(int index, Object value) { 34 | fields[index] = value; 35 | } 36 | public Object method(int index) { 37 | return classInfo.method(this, index); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/chap12/SymbolThis.java: -------------------------------------------------------------------------------- 1 | package chap12; 2 | import stone.StoneException; 3 | import chap11.Symbols; 4 | 5 | public class SymbolThis extends Symbols { 6 | public static final String NAME = "this"; 7 | public SymbolThis(Symbols outer) { 8 | super(outer); 9 | add(NAME); 10 | } 11 | @Override public int putNew(String key) { 12 | throw new StoneException("fatal"); 13 | } 14 | @Override public Location put(String key) { 15 | Location loc = outer.put(key); 16 | if (loc.nest >= 0) 17 | loc.nest++; 18 | return loc; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/chap13/Code.java: -------------------------------------------------------------------------------- 1 | package chap13; 2 | 3 | public class Code { 4 | protected StoneVM svm; 5 | protected int codeSize; 6 | protected int numOfStrings; 7 | protected int nextReg; 8 | protected int frameSize; 9 | 10 | public Code(StoneVM stoneVm) { 11 | svm = stoneVm; 12 | codeSize = 0; 13 | numOfStrings = 0; 14 | } 15 | public int position() { return codeSize; } 16 | public void set(short value, int pos) { 17 | svm.code()[pos] = (byte)(value >>> 8); 18 | svm.code()[pos + 1] = (byte)value; 19 | } 20 | public void add(byte b) { 21 | svm.code()[codeSize++] = b; 22 | } 23 | public void add(short i) { 24 | add((byte)(i >>> 8)); 25 | add((byte)i); 26 | } 27 | public void add(int i) { 28 | add((byte)(i >>> 24)); 29 | add((byte)(i >>> 16)); 30 | add((byte)(i >>> 8)); 31 | add((byte)i); 32 | } 33 | public int record(String s) { 34 | svm.strings()[numOfStrings] = s; 35 | return numOfStrings++; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/chap13/HeapMemory.java: -------------------------------------------------------------------------------- 1 | package chap13; 2 | 3 | public interface HeapMemory { 4 | Object read(int index); 5 | void write(int index, Object v); 6 | } 7 | -------------------------------------------------------------------------------- /src/chap13/Opcode.java: -------------------------------------------------------------------------------- 1 | package chap13; 2 | import stone.StoneException; 3 | 4 | public class Opcode { 5 | public static final byte ICONST = 1; // load an integer 6 | public static final byte BCONST = 2; // load an 8bit (1byte) integer 7 | public static final byte SCONST = 3; // load a character string 8 | public static final byte MOVE = 4; // move a value 9 | public static final byte GMOVE = 5; // move a value (global variable) 10 | public static final byte IFZERO = 6; // branch if false 11 | public static final byte GOTO = 7; // always branch 12 | public static final byte CALL = 8; // call a function 13 | public static final byte RETURN = 9; // return 14 | public static final byte SAVE = 10; // save all registers 15 | public static final byte RESTORE = 11; // restore all registers 16 | public static final byte NEG = 12; // arithmetic negation 17 | public static final byte ADD = 13; // add 18 | public static final byte SUB = 14; // subtract 19 | public static final byte MUL = 15; // multiply 20 | public static final byte DIV = 16; // divide 21 | public static final byte REM = 17; // remainder 22 | public static final byte EQUAL = 18; // equal 23 | public static final byte MORE = 19; // more than 24 | public static final byte LESS = 20; // less than 25 | 26 | public static byte encodeRegister(int reg) { 27 | if (reg > StoneVM.NUM_OF_REG) 28 | throw new StoneException("too many registers required"); 29 | else 30 | return (byte)-(reg + 1); 31 | } 32 | public static int decodeRegister(byte operand) { return -1 - operand; } 33 | public static byte encodeOffset(int offset) { 34 | if (offset > Byte.MAX_VALUE) 35 | throw new StoneException("too big byte offset"); 36 | else 37 | return (byte)offset; 38 | } 39 | public static short encodeShortOffset(int offset) { 40 | if (offset < Short.MIN_VALUE || Short.MAX_VALUE < offset) 41 | throw new StoneException("too big short offset"); 42 | else 43 | return (short)offset; 44 | } 45 | public static int decodeOffset(byte operand) { return operand; } 46 | public static boolean isRegister(byte operand) { return operand < 0; } 47 | public static boolean isOffset(byte operand) { return operand >= 0; } 48 | } 49 | -------------------------------------------------------------------------------- /src/chap13/StoneVM.java: -------------------------------------------------------------------------------- 1 | package chap13; 2 | import static chap13.Opcode.*; 3 | import chap8.NativeFunction; 4 | import stone.StoneException; 5 | import stone.ast.ASTree; 6 | import stone.ast.ASTList; 7 | import java.util.ArrayList; 8 | 9 | public class StoneVM { 10 | protected byte[] code; 11 | protected Object[] stack; 12 | protected String[] strings; 13 | protected HeapMemory heap; 14 | 15 | public int pc, fp, sp, ret; 16 | protected Object[] registers; 17 | public final static int NUM_OF_REG = 6; 18 | public final static int SAVE_AREA_SIZE = NUM_OF_REG + 2; 19 | 20 | public final static int TRUE = 1; 21 | public final static int FALSE = 0; 22 | 23 | public StoneVM(int codeSize, int stackSize, int stringsSize, HeapMemory hm) { 24 | code = new byte[codeSize]; 25 | stack = new Object[stackSize]; 26 | strings = new String[stringsSize]; 27 | registers = new Object[NUM_OF_REG]; 28 | heap = hm; 29 | } 30 | public Object getReg(int i) { return registers[i]; } 31 | public void setReg(int i, Object value) { registers[i] = value; } 32 | public String[] strings() { return strings; } 33 | public byte[] code() { return code; } 34 | public Object[] stack() { return stack; } 35 | public HeapMemory heap() { return heap; } 36 | 37 | public void run(int entry) { 38 | pc = entry; 39 | fp = 0; 40 | sp = 0; 41 | ret = -1; 42 | while (pc >= 0) 43 | mainLoop(); 44 | } 45 | protected void mainLoop() { 46 | switch (code[pc]) { 47 | case ICONST : 48 | registers[decodeRegister(code[pc + 5])] = readInt(code, pc + 1); 49 | pc += 6; 50 | break; 51 | case BCONST : 52 | registers[decodeRegister(code[pc + 2])] = (int)code[pc + 1]; 53 | pc += 3; 54 | break; 55 | case SCONST : 56 | registers[decodeRegister(code[pc + 3])] 57 | = strings[readShort(code, pc + 1)]; 58 | pc += 4; 59 | break; 60 | case MOVE : 61 | moveValue(); 62 | break; 63 | case GMOVE : 64 | moveHeapValue(); 65 | break; 66 | case IFZERO : { 67 | Object value = registers[decodeRegister(code[pc + 1])]; 68 | if (value instanceof Integer && ((Integer)value).intValue() == 0) 69 | pc += readShort(code, pc + 2); 70 | else 71 | pc += 4; 72 | break; 73 | } 74 | case GOTO : 75 | pc += readShort(code, pc + 1); 76 | break; 77 | case CALL : 78 | callFunction(); 79 | break; 80 | case RETURN : 81 | pc = ret; 82 | break; 83 | case SAVE : 84 | saveRegisters(); 85 | break; 86 | case RESTORE : 87 | restoreRegisters(); 88 | break; 89 | case NEG : { 90 | int reg = decodeRegister(code[pc + 1]); 91 | Object v = registers[reg]; 92 | if (v instanceof Integer) 93 | registers[reg] = -((Integer)v).intValue(); 94 | else 95 | throw new StoneException("bad operand value"); 96 | pc += 2; 97 | break; 98 | } 99 | default : 100 | if (code[pc] > LESS) 101 | throw new StoneException("bad instruction"); 102 | else 103 | computeNumber(); 104 | break; 105 | } 106 | } 107 | protected void moveValue() { 108 | byte src = code[pc + 1]; 109 | byte dest = code[pc + 2]; 110 | Object value; 111 | if (isRegister(src)) 112 | value = registers[decodeRegister(src)]; 113 | else 114 | value = stack[fp + decodeOffset(src)]; 115 | if (isRegister(dest)) 116 | registers[decodeRegister(dest)] = value; 117 | else 118 | stack[fp + decodeOffset(dest)] = value; 119 | pc += 3; 120 | } 121 | protected void moveHeapValue() { 122 | byte rand = code[pc + 1]; 123 | if (isRegister(rand)) { 124 | int dest = readShort(code, pc + 2); 125 | heap.write(dest, registers[decodeRegister(rand)]); 126 | } 127 | else { 128 | int src = readShort(code, pc + 1); 129 | registers[decodeRegister(code[pc + 3])] = heap.read(src); 130 | } 131 | pc += 4; 132 | } 133 | protected void callFunction() { 134 | Object value = registers[decodeRegister(code[pc + 1])]; 135 | int numOfArgs = code[pc + 2]; 136 | if (value instanceof VmFunction 137 | && ((VmFunction)value).parameters().size() == numOfArgs) { 138 | ret = pc + 3; 139 | pc = ((VmFunction)value).entry(); 140 | } 141 | else if (value instanceof NativeFunction 142 | && ((NativeFunction)value).numOfParameters() == numOfArgs) { 143 | Object[] args = new Object[numOfArgs]; 144 | for (int i = 0; i < numOfArgs; i++) 145 | args[i] = stack[sp + i]; 146 | stack[sp] = ((NativeFunction)value).invoke(args, 147 | new ASTList(new ArrayList())); 148 | pc += 3; 149 | } 150 | else 151 | throw new StoneException("bad function call"); 152 | } 153 | protected void saveRegisters() { 154 | int size = decodeOffset(code[pc + 1]); 155 | int dest = size + sp; 156 | for (int i = 0; i < NUM_OF_REG; i++) 157 | stack[dest++] = registers[i]; 158 | stack[dest++] = fp; 159 | fp = sp; 160 | sp += size + SAVE_AREA_SIZE; 161 | stack[dest++] = ret; 162 | pc += 2; 163 | } 164 | protected void restoreRegisters() { 165 | int dest = decodeOffset(code[pc + 1]) + fp; 166 | for (int i = 0; i < NUM_OF_REG; i++) 167 | registers[i] = stack[dest++]; 168 | sp = fp; 169 | fp = ((Integer)stack[dest++]).intValue(); 170 | ret = ((Integer)stack[dest++]).intValue(); 171 | pc += 2; 172 | } 173 | protected void computeNumber() { 174 | int left = decodeRegister(code[pc + 1]); 175 | int right = decodeRegister(code[pc + 2]); 176 | Object v1 = registers[left]; 177 | Object v2 = registers[right]; 178 | boolean areNumbers = v1 instanceof Integer && v2 instanceof Integer; 179 | if (code[pc] == ADD && !areNumbers) 180 | registers[left] = String.valueOf(v1) + String.valueOf(v2); 181 | else if (code[pc] == EQUAL && !areNumbers) { 182 | if (v1 == null) 183 | registers[left] = v2 == null ? TRUE : FALSE; 184 | else 185 | registers[left] = v1.equals(v2) ? TRUE : FALSE; 186 | } 187 | else { 188 | if (!areNumbers) 189 | throw new StoneException("bad operand value"); 190 | int i1 = ((Integer)v1).intValue(); 191 | int i2 = ((Integer)v2).intValue(); 192 | int i3; 193 | switch (code[pc]) { 194 | case ADD : 195 | i3 = i1 + i2; 196 | break; 197 | case SUB: 198 | i3 = i1 - i2; 199 | break; 200 | case MUL: 201 | i3 = i1 * i2; 202 | break; 203 | case DIV: 204 | i3 = i1 / i2; 205 | break; 206 | case REM: 207 | i3 = i1 % i2; 208 | break; 209 | case EQUAL: 210 | i3 = i1 == i2 ? TRUE : FALSE; 211 | break; 212 | case MORE: 213 | i3 = i1 > i2 ? TRUE : FALSE; 214 | break; 215 | case LESS: 216 | i3 = i1 < i2 ? TRUE : FALSE; 217 | break; 218 | default: 219 | throw new StoneException("never reach here"); 220 | } 221 | registers[left] = i3; 222 | } 223 | pc += 3; 224 | } 225 | 226 | public static int readInt(byte[] array, int index) { 227 | return (array[index] << 24) | ((array[index + 1] & 0xff) << 16) 228 | | ((array[index + 2] & 0xff) << 8) | (array[index + 3] & 0xff); 229 | } 230 | public static int readShort(byte[] array, int index) { 231 | return (array[index] << 8) | (array[index + 1] & 0xff); 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /src/chap13/StoneVMEnv.java: -------------------------------------------------------------------------------- 1 | package chap13; 2 | import chap11.ResizableArrayEnv; 3 | 4 | public class StoneVMEnv extends ResizableArrayEnv implements HeapMemory { 5 | protected StoneVM svm; 6 | protected Code code; 7 | public StoneVMEnv(int codeSize, int stackSize, int stringsSize) { 8 | svm = new StoneVM(codeSize, stackSize, stringsSize, this); 9 | code = new Code(svm); 10 | } 11 | public StoneVM stoneVM() { return svm; } 12 | public Code code() { return code; } 13 | public Object read(int index) { return values[index]; } 14 | public void write(int index, Object v) { values[index] = v; } 15 | } 16 | -------------------------------------------------------------------------------- /src/chap13/VmEvaluator.java: -------------------------------------------------------------------------------- 1 | package chap13; 2 | import java.util.List; 3 | import stone.StoneException; 4 | import stone.Token; 5 | import chap11.EnvOptimizer; 6 | import chap6.Environment; 7 | import chap6.BasicEvaluator.ASTreeEx; 8 | import chap7.FuncEvaluator; 9 | import javassist.gluonj.*; 10 | import static chap13.Opcode.*; 11 | import static javassist.gluonj.GluonJ.revise; 12 | import stone.ast.*; 13 | 14 | @Require(EnvOptimizer.class) 15 | @Reviser public class VmEvaluator { 16 | @Reviser public static interface EnvEx3 extends EnvOptimizer.EnvEx2 { 17 | StoneVM stoneVM(); 18 | Code code(); 19 | } 20 | @Reviser public static abstract class ASTreeVmEx extends ASTree { 21 | public void compile(Code c) {} 22 | } 23 | @Reviser public static class ASTListEx extends ASTList { 24 | public ASTListEx(List c) { super(c); } 25 | public void compile(Code c) { 26 | for (ASTree t: this) 27 | ((ASTreeVmEx)t).compile(c); 28 | } 29 | } 30 | @Reviser public static class DefStmntVmEx extends EnvOptimizer.DefStmntEx { 31 | public DefStmntVmEx(List c) { super(c); } 32 | @Override public Object eval(Environment env) { 33 | String funcName = name(); 34 | EnvEx3 vmenv = (EnvEx3)env; 35 | Code code = vmenv.code(); 36 | int entry = code.position(); 37 | compile(code); 38 | ((EnvEx3)env).putNew(funcName, new VmFunction(parameters(), body(), 39 | env, entry)); 40 | return funcName; 41 | } 42 | public void compile(Code c) { 43 | c.nextReg = 0; 44 | c.frameSize = size + StoneVM.SAVE_AREA_SIZE; 45 | c.add(SAVE); 46 | c.add(encodeOffset(size)); 47 | ((ASTreeVmEx)revise(body())).compile(c); 48 | c.add(MOVE); 49 | c.add(encodeRegister(c.nextReg - 1)); 50 | c.add(encodeOffset(0)); 51 | c.add(RESTORE); 52 | c.add(encodeOffset(size)); 53 | c.add(RETURN); 54 | } 55 | } 56 | @Reviser public static class ParamsEx2 extends EnvOptimizer.ParamsEx { 57 | public ParamsEx2(List c) { super(c); } 58 | @Override public void eval(Environment env, int index, Object value) { 59 | StoneVM vm = ((EnvEx3)env).stoneVM(); 60 | vm.stack()[offsets[index]] = value; 61 | } 62 | } 63 | @Reviser public static class NumberEx extends NumberLiteral { 64 | public NumberEx(Token t) { super(t); } 65 | public void compile(Code c) { 66 | int v = value(); 67 | if (Byte.MIN_VALUE <= v && v <= Byte.MAX_VALUE) { 68 | c.add(BCONST); 69 | c.add((byte)v); 70 | } 71 | else { 72 | c.add(ICONST); 73 | c.add(v); 74 | } 75 | c.add(encodeRegister(c.nextReg++)); 76 | } 77 | } 78 | @Reviser public static class StringEx extends StringLiteral { 79 | public StringEx(Token t) { super(t); } 80 | public void compile(Code c) { 81 | int i = c.record(value()); 82 | c.add(SCONST); 83 | c.add(encodeShortOffset(i)); 84 | c.add(encodeRegister(c.nextReg++)); 85 | } 86 | } 87 | @Reviser public static class NameEx2 extends EnvOptimizer.NameEx { 88 | public NameEx2(Token t) { super(t); } 89 | public void compile(Code c) { 90 | if (nest > 0) { 91 | c.add(GMOVE); 92 | c.add(encodeShortOffset(index)); 93 | c.add(encodeRegister(c.nextReg++)); 94 | } 95 | else { 96 | c.add(MOVE); 97 | c.add(encodeOffset(index)); 98 | c.add(encodeRegister(c.nextReg++)); 99 | } 100 | } 101 | public void compileAssign(Code c) { 102 | if (nest > 0) { 103 | c.add(GMOVE); 104 | c.add(encodeRegister(c.nextReg - 1)); 105 | c.add(encodeShortOffset(index)); 106 | } 107 | else { 108 | c.add(MOVE); 109 | c.add(encodeRegister(c.nextReg - 1)); 110 | c.add(encodeOffset(index)); 111 | } 112 | } 113 | } 114 | @Reviser public static class NegativeEx extends NegativeExpr { 115 | public NegativeEx(List c) { super(c); } 116 | public void compile(Code c) { 117 | ((ASTreeVmEx)operand()).compile(c); 118 | c.add(NEG); 119 | c.add(encodeRegister(c.nextReg - 1)); 120 | } 121 | } 122 | @Reviser public static class BinaryEx extends BinaryExpr { 123 | public BinaryEx(List c) { super(c); } 124 | public void compile(Code c) { 125 | String op = operator(); 126 | if (op.equals("=")) { 127 | ASTree l = left(); 128 | if (l instanceof Name) { 129 | ((ASTreeVmEx)right()).compile(c); 130 | ((NameEx2)l).compileAssign(c); 131 | } 132 | else 133 | throw new StoneException("bad assignment", this); 134 | } 135 | else { 136 | ((ASTreeVmEx)left()).compile(c); 137 | ((ASTreeVmEx)right()).compile(c); 138 | c.add(getOpcode(op)); 139 | c.add(encodeRegister(c.nextReg - 2)); 140 | c.add(encodeRegister(c.nextReg - 1)); 141 | c.nextReg--; 142 | } 143 | } 144 | protected byte getOpcode(String op) { 145 | if (op.equals("+")) 146 | return ADD; 147 | else if (op.equals("-")) 148 | return SUB; 149 | else if (op.equals("*")) 150 | return MUL; 151 | else if (op.equals("/")) 152 | return DIV; 153 | else if (op.equals("%")) 154 | return REM; 155 | else if (op.equals("==")) 156 | return EQUAL; 157 | else if (op.equals(">")) 158 | return MORE; 159 | else if (op.equals("<")) 160 | return LESS; 161 | else 162 | throw new StoneException("bad operator", this); 163 | } 164 | } 165 | @Reviser public static class PrimaryVmEx extends FuncEvaluator.PrimaryEx { 166 | public PrimaryVmEx(List c) { super(c); } 167 | public void compile(Code c) { 168 | compileSubExpr(c, 0); 169 | } 170 | public void compileSubExpr(Code c, int nest) { 171 | if (hasPostfix(nest)) { 172 | compileSubExpr(c, nest + 1); 173 | ((ASTreeVmEx)revise(postfix(nest))).compile(c); 174 | } 175 | else 176 | ((ASTreeVmEx)operand()).compile(c); 177 | } 178 | } 179 | @Reviser public static class ArgumentsEx extends Arguments { 180 | public ArgumentsEx(List c) { super(c); } 181 | public void compile(Code c) { 182 | int newOffset = c.frameSize; 183 | int numOfArgs = 0; 184 | for (ASTree a: this) { 185 | ((ASTreeVmEx)a).compile(c); 186 | c.add(MOVE); 187 | c.add(encodeRegister(--c.nextReg)); 188 | c.add(encodeOffset(newOffset++)); 189 | numOfArgs++; 190 | } 191 | c.add(CALL); 192 | c.add(encodeRegister(--c.nextReg)); 193 | c.add(encodeOffset(numOfArgs)); 194 | c.add(MOVE); 195 | c.add(encodeOffset(c.frameSize)); 196 | c.add(encodeRegister(c.nextReg++)); 197 | } 198 | public Object eval(Environment env, Object value) { 199 | if (!(value instanceof VmFunction)) 200 | throw new StoneException("bad function", this); 201 | VmFunction func = (VmFunction)value; 202 | ParameterList params = func.parameters(); 203 | if (size() != params.size()) 204 | throw new StoneException("bad number of arguments", this); 205 | int num = 0; 206 | for (ASTree a: this) 207 | ((ParamsEx2)params).eval(env, num++, ((ASTreeEx)a).eval(env)); 208 | StoneVM svm = ((EnvEx3)env).stoneVM(); 209 | svm.run(func.entry()); 210 | return svm.stack()[0]; 211 | } 212 | } 213 | @Reviser public static class BlockEx extends BlockStmnt { 214 | public BlockEx(List c) { super(c); } 215 | public void compile(Code c) { 216 | if (this.numChildren() > 0) { 217 | int initReg = c.nextReg; 218 | for (ASTree a: this) { 219 | c.nextReg = initReg; 220 | ((ASTreeVmEx)a).compile(c); 221 | } 222 | } 223 | else { 224 | c.add(BCONST); 225 | c.add((byte)0); 226 | c.add(encodeRegister(c.nextReg++)); 227 | } 228 | } 229 | } 230 | @Reviser public static class IfEx extends IfStmnt { 231 | public IfEx(List c) { super(c); } 232 | public void compile(Code c) { 233 | ((ASTreeVmEx)condition()).compile(c); 234 | int pos = c.position(); 235 | c.add(IFZERO); 236 | c.add(encodeRegister(--c.nextReg)); 237 | c.add(encodeShortOffset(0)); 238 | int oldReg = c.nextReg; 239 | ((ASTreeVmEx)thenBlock()).compile(c); 240 | int pos2 = c.position(); 241 | c.add(GOTO); 242 | c.add(encodeShortOffset(0)); 243 | c.set(encodeShortOffset(c.position() - pos), pos + 2); 244 | ASTree b = elseBlock(); 245 | c.nextReg = oldReg; 246 | if (b != null) 247 | ((ASTreeVmEx)b).compile(c); 248 | else { 249 | c.add(BCONST); 250 | c.add((byte)0); 251 | c.add(encodeRegister(c.nextReg++)); 252 | } 253 | c.set(encodeShortOffset(c.position() - pos2), pos2 + 1); 254 | } 255 | } 256 | @Reviser public static class WhileEx extends WhileStmnt { 257 | public WhileEx(List c) { super(c); } 258 | public void compile(Code c) { 259 | int oldReg = c.nextReg; 260 | c.add(BCONST); 261 | c.add((byte)0); 262 | c.add(encodeRegister(c.nextReg++)); 263 | int pos = c.position(); 264 | ((ASTreeVmEx)condition()).compile(c); 265 | int pos2 = c.position(); 266 | c.add(IFZERO); 267 | c.add(encodeRegister(--c.nextReg)); 268 | c.add(encodeShortOffset(0)); 269 | c.nextReg = oldReg; 270 | ((ASTreeVmEx)body()).compile(c); 271 | int pos3= c.position(); 272 | c.add(GOTO); 273 | c.add(encodeShortOffset(pos - pos3)); 274 | c.set(encodeShortOffset(c.position() - pos2), pos2 + 2); 275 | } 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /src/chap13/VmFunction.java: -------------------------------------------------------------------------------- 1 | package chap13; 2 | import stone.ast.BlockStmnt; 3 | import stone.ast.ParameterList; 4 | import chap6.Environment; 5 | import chap7.Function; 6 | 7 | public class VmFunction extends Function { 8 | protected int entry; 9 | public VmFunction(ParameterList parameters, BlockStmnt body, 10 | Environment env, int entry) 11 | { 12 | super(parameters, body, env); 13 | this.entry = entry; 14 | } 15 | public int entry() { return entry; } 16 | } 17 | -------------------------------------------------------------------------------- /src/chap13/VmInterpreter.java: -------------------------------------------------------------------------------- 1 | package chap13; 2 | import stone.FuncParser; 3 | import stone.ParseException; 4 | import chap11.EnvOptInterpreter; 5 | import chap8.Natives; 6 | 7 | public class VmInterpreter extends EnvOptInterpreter { 8 | public static void main(String[] args) throws ParseException { 9 | run(new FuncParser(), 10 | new Natives().environment(new StoneVMEnv(100000, 100000, 1000))); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/chap13/VmRunner.java: -------------------------------------------------------------------------------- 1 | package chap13; 2 | import javassist.gluonj.util.Loader; 3 | import chap8.NativeEvaluator; 4 | 5 | public class VmRunner { 6 | public static void main(String[] args) throws Throwable { 7 | Loader.run(VmInterpreter.class, args, VmEvaluator.class, 8 | NativeEvaluator.class); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/chap14/InferFuncTypes.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import java.util.List; 3 | import chap14.TypeInfo.FunctionType; 4 | import chap14.TypeInfo.UnknownType; 5 | import chap14.InferTypes.UnknownTypeEx; 6 | import stone.ast.ASTree; 7 | import javassist.gluonj.Require; 8 | import javassist.gluonj.Reviser; 9 | 10 | @Require({TypeChecker.class, InferTypes.class}) 11 | @Reviser public class InferFuncTypes { 12 | @Reviser public static class DefStmntEx3 extends TypeChecker.DefStmntEx2 { 13 | public DefStmntEx3(List c) { super(c); } 14 | @Override public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 15 | FunctionType func = super.typeCheck(tenv).toFunctionType(); 16 | for (TypeInfo t: func.parameterTypes) 17 | fixUnknown(t); 18 | fixUnknown(func.returnType); 19 | return func; 20 | } 21 | protected void fixUnknown(TypeInfo t) { 22 | if (t.isUnknownType()) { 23 | UnknownType ut = t.toUnknownType(); 24 | if (!((UnknownTypeEx)ut).resolved()) 25 | ((UnknownTypeEx)ut).setType(TypeInfo.ANY); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/chap14/InferRunner.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | 3 | import javassist.gluonj.util.Loader; 4 | import chap8.NativeEvaluator; 5 | 6 | public class InferRunner { 7 | public static void main(String[] args) throws Throwable { 8 | Loader.run(TypedInterpreter.class, args, InferFuncTypes.class, 9 | NativeEvaluator.class); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/chap14/InferTypes.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import java.util.ArrayList; 3 | import java.util.LinkedList; 4 | import java.util.List; 5 | import stone.ast.ASTree; 6 | import javassist.gluonj.Reviser; 7 | import chap14.TypeInfo.UnknownType; 8 | 9 | @Reviser public class InferTypes { 10 | @Reviser public static class TypeInfoEx extends TypeInfo { 11 | @Override 12 | public void assertSubtypeOf(TypeInfo type, TypeEnv tenv, ASTree where) 13 | throws TypeException 14 | { 15 | if (type.isUnknownType()) 16 | ((UnknownTypeEx)type.toUnknownType()).assertSupertypeOf(this, 17 | tenv, where); 18 | else 19 | super.assertSubtypeOf(type, tenv, where); 20 | } 21 | @Override public TypeInfo union(TypeInfo right, TypeEnv tenv) { 22 | if (right.isUnknownType()) 23 | return right.union(this, tenv); 24 | else 25 | return super.union(right, tenv); 26 | } 27 | @Override public TypeInfo plus(TypeInfo right, TypeEnv tenv) { 28 | if (right.isUnknownType()) 29 | return right.plus(this, tenv); 30 | else 31 | return super.plus(right, tenv); 32 | } 33 | } 34 | @Reviser public static class UnknownTypeEx extends TypeInfo.UnknownType { 35 | protected TypeInfo type = null; 36 | public boolean resolved() { return type != null; } 37 | public void setType(TypeInfo t) { type = t; } 38 | @Override public TypeInfo type() { return type == null ? ANY : type; } 39 | @Override public void assertSubtypeOf(TypeInfo t, TypeEnv tenv, 40 | ASTree where) throws TypeException 41 | { 42 | if (resolved()) 43 | type.assertSubtypeOf(t, tenv, where); 44 | else 45 | ((TypeEnvEx)tenv).addEquation(this, t); 46 | } 47 | public void assertSupertypeOf(TypeInfo t, TypeEnv tenv, ASTree where) 48 | throws TypeException 49 | { 50 | if (resolved()) 51 | t.assertSubtypeOf(type, tenv, where); 52 | else 53 | ((TypeEnvEx)tenv).addEquation(this, t); 54 | } 55 | @Override public TypeInfo union(TypeInfo right, TypeEnv tenv) { 56 | if (resolved()) 57 | return type.union(right, tenv); 58 | else { 59 | ((TypeEnvEx)tenv).addEquation(this, right); 60 | return right; 61 | } 62 | } 63 | @Override public TypeInfo plus(TypeInfo right, TypeEnv tenv) { 64 | if (resolved()) 65 | return type.plus(right, tenv); 66 | else { 67 | ((TypeEnvEx)tenv).addEquation(this, INT); 68 | return right.plus(INT, tenv); 69 | } 70 | } 71 | } 72 | @Reviser public static class TypeEnvEx extends TypeEnv { 73 | public static class Equation extends ArrayList {} 74 | protected List equations = new LinkedList(); 75 | public void addEquation(UnknownType t1, TypeInfo t2) { 76 | // assert t1.unknown() == true 77 | if (t2.isUnknownType()) 78 | if (((UnknownTypeEx)t2.toUnknownType()).resolved()) 79 | t2 = t2.type(); 80 | Equation eq = find(t1); 81 | if (t2.isUnknownType()) 82 | eq.add(t2.toUnknownType()); 83 | else { 84 | for (UnknownType t: eq) 85 | ((UnknownTypeEx)t).setType(t2); 86 | equations.remove(eq); 87 | } 88 | } 89 | protected Equation find(UnknownType t) { 90 | for (Equation e: equations) 91 | if (e.contains(t)) 92 | return e; 93 | Equation e = new Equation(); 94 | e.add(t); 95 | equations.add(e); 96 | return e; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/chap14/JavaFunction.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import stone.StoneException; 3 | import chap7.Function; 4 | 5 | public class JavaFunction extends Function { 6 | protected String className; 7 | protected Class clazz; 8 | public JavaFunction(String name, String method, JavaLoader loader) { 9 | super(null, null, null); 10 | className = className(name); 11 | clazz = loader.load(className, method); 12 | } 13 | public static String className(String name) { 14 | return "chap14.java." + name; 15 | } 16 | public Object invoke(Object[] args) { 17 | try { 18 | return clazz.getDeclaredMethods()[0].invoke(null, args); 19 | } catch (Exception e) { 20 | throw new StoneException(e.getMessage()); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/chap14/JavaLoader.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import stone.StoneException; 3 | import javassist.CannotCompileException; 4 | import javassist.ClassPool; 5 | import javassist.CtClass; 6 | import javassist.CtMethod; 7 | 8 | public class JavaLoader { 9 | protected ClassLoader loader; 10 | protected ClassPool cpool; 11 | public JavaLoader() { 12 | cpool = new ClassPool(null); 13 | cpool.appendSystemPath(); 14 | loader = new ClassLoader(this.getClass().getClassLoader()) {}; 15 | } 16 | public Class load(String className, String method) { 17 | // System.out.println(method); 18 | CtClass cc = cpool.makeClass(className); 19 | try { 20 | cc.addMethod(CtMethod.make(method, cc)); 21 | return cc.toClass(loader, null); 22 | } catch (CannotCompileException e) { 23 | throw new StoneException(e.getMessage()); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/chap14/JavaRunner.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | 3 | import javassist.gluonj.util.Loader; 4 | import chap8.NativeEvaluator; 5 | 6 | public class JavaRunner { 7 | public static void main(String[] args) throws Throwable { 8 | Loader.run(TypedInterpreter.class, args, ToJava.class, 9 | InferFuncTypes.class, NativeEvaluator.class); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/chap14/Runtime.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import chap11.ArrayEnv; 3 | 4 | public class Runtime { 5 | public static int eq(Object a, Object b) { 6 | if (a == null) 7 | return b == null ? 1 : 0; 8 | else 9 | return a.equals(b) ? 1 : 0; 10 | } 11 | public static Object plus(Object a, Object b) { 12 | if (a instanceof Integer && b instanceof Integer) 13 | return ((Integer)a).intValue() + ((Integer)b).intValue(); 14 | else 15 | return a.toString().concat(b.toString()); 16 | } 17 | public static int writeInt(ArrayEnv env, int index, int value) { 18 | env.put(0, index, value); 19 | return value; 20 | } 21 | public static String writeString(ArrayEnv env, int index, String value) { 22 | env.put(0, index, value); 23 | return value; 24 | } 25 | public static Object writeAny(ArrayEnv env, int index, Object value) { 26 | env.put(0, index, value); 27 | return value; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/chap14/ToJava.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import java.util.ArrayList; 3 | import java.util.List; 4 | import chap11.ArrayEnv; 5 | import chap11.EnvOptimizer; 6 | import chap6.Environment; 7 | import chap7.FuncEvaluator; 8 | import stone.StoneException; 9 | import stone.Token; 10 | import stone.ast.*; 11 | import javassist.gluonj.Require; 12 | import javassist.gluonj.Reviser; 13 | import static javassist.gluonj.GluonJ.revise; 14 | 15 | @Require(TypeChecker.class) 16 | @Reviser public class ToJava { 17 | public static final String METHOD = "m"; 18 | public static final String LOCAL = "v"; 19 | public static final String ENV = "env"; 20 | public static final String RESULT = "res"; 21 | public static final String ENV_TYPE = "chap11.ArrayEnv"; 22 | 23 | public static String translateExpr(ASTree ast, TypeInfo from, TypeInfo to) { 24 | return translateExpr(((ASTreeEx)ast).translate(null), from, to); 25 | } 26 | public static String translateExpr(String expr, TypeInfo from, 27 | TypeInfo to) 28 | { 29 | from = from.type(); 30 | to = to.type(); 31 | if (from == TypeInfo.INT) { 32 | if (to == TypeInfo.ANY) 33 | return "new Integer(" + expr + ")"; 34 | else if (to == TypeInfo.STRING) 35 | return "Integer.toString(" + expr + ")"; 36 | } 37 | else if (from == TypeInfo.ANY) 38 | if (to == TypeInfo.STRING) 39 | return expr + ".toString()"; 40 | else if (to == TypeInfo.INT) 41 | return "((Integer)" + expr + ").intValue()"; 42 | return expr; 43 | } 44 | public static String returnZero(TypeInfo to) { 45 | if (to.type() == TypeInfo.ANY) 46 | return RESULT + "=new Integer(0);"; 47 | else 48 | return RESULT + "=0;"; 49 | } 50 | 51 | @Reviser public static interface EnvEx3 extends EnvOptimizer.EnvEx2 { 52 | JavaLoader javaLoader(); 53 | } 54 | @Reviser public static class ArrayEnvEx extends ArrayEnv { 55 | public ArrayEnvEx(int size, Environment out) { super(size, out); } 56 | protected JavaLoader jloader = new JavaLoader(); 57 | public JavaLoader javaLoader() { return jloader; } 58 | } 59 | @Reviser public static abstract class ASTreeEx extends ASTree { 60 | public String translate(TypeInfo result) { return ""; } 61 | } 62 | @Reviser public static class NumberEx extends NumberLiteral { 63 | public NumberEx(Token t) { super(t); } 64 | public String translate(TypeInfo result) { 65 | return Integer.toString(value()); 66 | } 67 | } 68 | @Reviser public static class StringEx extends StringLiteral { 69 | public StringEx(Token t) { super(t); } 70 | public String translate(TypeInfo result) { 71 | StringBuilder code = new StringBuilder(); 72 | String literal = value(); 73 | code.append('"'); 74 | for (int i = 0; i < literal.length(); i++) { 75 | char c = literal.charAt(i); 76 | if (c == '"') 77 | code.append("\\\""); 78 | else if (c == '\\') 79 | code.append("\\\\"); 80 | else if (c == '\n') 81 | code.append("\\n"); 82 | else 83 | code.append(c); 84 | } 85 | code.append('"'); 86 | return code.toString(); 87 | } 88 | } 89 | @Reviser public static class NameEx3 extends TypeChecker.NameEx2 { 90 | public NameEx3(Token t) { super(t); } 91 | public String translate(TypeInfo result) { 92 | if (type.isFunctionType()) 93 | return JavaFunction.className(name()) + "." + METHOD; 94 | else if (nest == 0) 95 | return LOCAL + index; 96 | else { 97 | String expr = ENV + ".get(0," + index + ")"; 98 | return translateExpr(expr, TypeInfo.ANY, type); 99 | } 100 | } 101 | public String translateAssign(TypeInfo valueType, ASTree right) { 102 | if (nest == 0) 103 | return "(" + LOCAL + index + "=" 104 | + translateExpr(right, valueType, type) + ")"; 105 | else { 106 | String value = ((ASTreeEx)right).translate(null); 107 | return "chap14.Runtime.write" + type.toString() 108 | + "(" + ENV + "," + index + "," + value + ")"; 109 | } 110 | } 111 | } 112 | @Reviser public static class NegativeEx extends NegativeExpr { 113 | public NegativeEx(List c) { super(c); } 114 | public String translate(TypeInfo result) { 115 | return "-" + ((ASTreeEx)operand()).translate(null); 116 | } 117 | } 118 | @Reviser public static class BinaryEx2 extends TypeChecker.BinaryEx { 119 | public BinaryEx2(List c) { super(c); } 120 | public String translate(TypeInfo result) { 121 | String op = operator(); 122 | if ("=".equals(op)) 123 | return ((NameEx3)left()).translateAssign(rightType, right()); 124 | else if (leftType.type() != TypeInfo.INT 125 | || rightType.type() != TypeInfo.INT) { 126 | String e1 = translateExpr(left(), leftType, TypeInfo.ANY); 127 | String e2 = translateExpr(right(), rightType, TypeInfo.ANY); 128 | if ("==".equals(op)) 129 | return "chap14.Runtime.eq(" + e1 + "," + e2 + ")"; 130 | else if ("+".equals(op)) { 131 | if (leftType.type() == TypeInfo.STRING 132 | || rightType.type() == TypeInfo.STRING) 133 | return e1 + "+" + e2; 134 | else 135 | return "chap14.Runtime.plus(" + e1 + "," + e2 + ")"; 136 | } 137 | else 138 | throw new StoneException("bad operator", this); 139 | } 140 | else { 141 | String expr = ((ASTreeEx)left()).translate(null) + op 142 | + ((ASTreeEx)right()).translate(null); 143 | if ("<".equals(op) || ">".equals(op) || "==".equals(op)) 144 | return "(" + expr + "?1:0)"; 145 | else 146 | return "(" + expr + ")"; 147 | } 148 | } 149 | } 150 | @Reviser public static class BlockEx2 extends TypeChecker.BlockEx { 151 | public BlockEx2(List c) { super(c); } 152 | public String translate(TypeInfo result) { 153 | ArrayList body = new ArrayList(); 154 | for (ASTree t: this) 155 | if (!(t instanceof NullStmnt)) 156 | body.add(t); 157 | StringBuilder code = new StringBuilder(); 158 | if (result != null && body.size() < 1) 159 | code.append(returnZero(result)); 160 | else 161 | for (int i = 0; i < body.size(); i++) 162 | translateStmnt(code, body.get(i), result, 163 | i == body.size() - 1); 164 | return code.toString(); 165 | } 166 | protected void translateStmnt(StringBuilder code, ASTree tree, 167 | TypeInfo result, boolean last) 168 | { 169 | if (isControlStmnt(tree)) 170 | code.append(((ASTreeEx)tree).translate(last ? result : null)); 171 | else 172 | if (last && result != null) 173 | code.append(RESULT).append('=') 174 | .append(translateExpr(tree, type, result)).append(";\n"); 175 | else if (isExprStmnt(tree)) 176 | code.append(((ASTreeEx)tree).translate(null)).append(";\n"); 177 | else 178 | throw new StoneException("bad expression statement", this); 179 | } 180 | protected static boolean isExprStmnt(ASTree tree) { 181 | if (tree instanceof BinaryExpr) 182 | return "=".equals(((BinaryExpr)tree).operator()); 183 | return tree instanceof PrimaryExpr || tree instanceof VarStmnt; 184 | } 185 | protected static boolean isControlStmnt(ASTree tree) { 186 | return tree instanceof BlockStmnt || tree instanceof IfStmnt 187 | || tree instanceof WhileStmnt; 188 | } 189 | } 190 | @Reviser public static class IfEx extends IfStmnt { 191 | public IfEx(List c) { super(c); } 192 | public String translate(TypeInfo result) { 193 | StringBuilder code = new StringBuilder(); 194 | code.append("if("); 195 | code.append(((ASTreeEx)condition()).translate(null)); 196 | code.append("!=0){\n"); 197 | code.append(((ASTreeEx)thenBlock()).translate(result)); 198 | code.append("} else {\n"); 199 | ASTree elseBk = elseBlock(); 200 | if (elseBk != null) 201 | code.append(((ASTreeEx)elseBk).translate(result)); 202 | else if (result != null) 203 | code.append(returnZero(result)); 204 | return code.append("}\n").toString(); 205 | } 206 | } 207 | @Reviser public static class WhileEx extends WhileStmnt { 208 | public WhileEx(List c) { super(c); } 209 | public String translate(TypeInfo result) { 210 | String code = "while(" + ((ASTreeEx)condition()).translate(null) 211 | + "!=0){\n" + ((ASTreeEx)body()).translate(result) 212 | + "}\n"; 213 | if (result == null) 214 | return code; 215 | else 216 | return returnZero(result) + "\n" + code; 217 | } 218 | } 219 | @Reviser public static class DefStmntEx3 extends TypeChecker.DefStmntEx2 { 220 | public DefStmntEx3(List c) { super(c); } 221 | @Override public Object eval(Environment env) { 222 | String funcName = name(); 223 | JavaFunction func = new JavaFunction(funcName, translate(null), 224 | ((EnvEx3)env).javaLoader()); 225 | ((EnvEx3)env).putNew(funcName, func); 226 | return funcName; 227 | } 228 | public String translate(TypeInfo result) { 229 | StringBuilder code = new StringBuilder("public static "); 230 | TypeInfo returnType = funcType.returnType; 231 | code.append(javaType(returnType)).append(' '); 232 | code.append(METHOD).append("(chap11.ArrayEnv ").append(ENV); 233 | for (int i = 0; i < funcType.parameterTypes.length; i++) { 234 | code.append(',').append(javaType(funcType.parameterTypes[i])) 235 | .append(' ').append(LOCAL).append(i); 236 | } 237 | code.append("){\n"); 238 | code.append(javaType(returnType)).append(' ').append(RESULT) 239 | .append(";\n"); 240 | for (int i = funcType.parameterTypes.length; i < size; i++) { 241 | TypeInfo t = bodyEnv.get(0, i); 242 | code.append(javaType(t)).append(' ').append(LOCAL).append(i); 243 | if (t.type() == TypeInfo.INT) 244 | code.append("=0;\n"); 245 | else 246 | code.append("=null;\n"); 247 | } 248 | code.append(((ASTreeEx)revise(body())).translate(returnType)); 249 | code.append("return ").append(RESULT).append(";}"); 250 | return code.toString(); 251 | } 252 | protected String javaType(TypeInfo t) { 253 | if (t.type() == TypeInfo.INT) 254 | return "int"; 255 | else if (t.type() == TypeInfo.STRING) 256 | return "String"; 257 | else 258 | return "Object"; 259 | } 260 | } 261 | @Reviser public static class PrimaryEx2 extends FuncEvaluator.PrimaryEx { 262 | public PrimaryEx2(List c) { super(c); } 263 | public String translate(TypeInfo result) { return translate(0); } 264 | public String translate(int nest) { 265 | if (hasPostfix(nest)) { 266 | String expr = translate(nest + 1); 267 | return ((PostfixEx)postfix(nest)).translate(expr); 268 | } 269 | else 270 | return ((ASTreeEx)operand()).translate(null); 271 | } 272 | } 273 | @Reviser public static abstract class PostfixEx extends Postfix { 274 | public PostfixEx(List c) { super(c); } 275 | public abstract String translate(String expr); 276 | } 277 | @Reviser public static class ArgumentsEx extends TypeChecker.ArgumentsEx { 278 | public ArgumentsEx(List c) { super(c); } 279 | public String translate(String expr) { 280 | StringBuilder code = new StringBuilder(expr); 281 | code.append('(').append(ENV); 282 | for (int i = 0; i < size(); i++) 283 | code.append(',') 284 | .append(translateExpr(child(i), argTypes[i], 285 | funcType.parameterTypes[i])); 286 | return code.append(')').toString(); 287 | } 288 | public Object eval(Environment env, Object value) { 289 | if (!(value instanceof JavaFunction)) 290 | throw new StoneException("bad function", this); 291 | JavaFunction func = (JavaFunction)value; 292 | Object[] args = new Object[numChildren() + 1]; 293 | args[0] = env; 294 | int num = 1; 295 | for (ASTree a: this) 296 | args[num++] = ((chap6.BasicEvaluator.ASTreeEx)a).eval(env); 297 | return func.invoke(args); 298 | } 299 | } 300 | @Reviser public static class VarStmntEx3 extends TypeChecker.VarStmntEx2 { 301 | public VarStmntEx3(List c) { super(c); } 302 | public String translate(TypeInfo result) { 303 | return LOCAL + index + "=" 304 | + translateExpr(initializer(), valueType, varType); 305 | } 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /src/chap14/TypeChecker.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import java.util.List; 3 | import chap7.FuncEvaluator; 4 | import chap11.EnvOptimizer; 5 | import stone.Token; 6 | import static javassist.gluonj.GluonJ.revise; 7 | import stone.ast.*; 8 | import javassist.gluonj.*; 9 | 10 | @Require(TypedEvaluator.class) 11 | @Reviser public class TypeChecker { 12 | @Reviser public static abstract class ASTreeTypeEx extends ASTree { 13 | public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 14 | return null; 15 | } 16 | } 17 | @Reviser public static class NumberEx extends NumberLiteral { 18 | public NumberEx(Token t) { super(t); } 19 | public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 20 | return TypeInfo.INT; 21 | } 22 | } 23 | @Reviser public static class StringEx extends StringLiteral { 24 | public StringEx(Token t) { super(t); } 25 | public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 26 | return TypeInfo.STRING; 27 | } 28 | } 29 | @Reviser public static class NameEx2 extends EnvOptimizer.NameEx { 30 | protected TypeInfo type; 31 | public NameEx2(Token t) { super(t); } 32 | public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 33 | type = tenv.get(nest, index); 34 | if (type == null) 35 | throw new TypeException("undefined name: " + name(), this); 36 | else 37 | return type; 38 | } 39 | public TypeInfo typeCheckForAssign(TypeEnv tenv, TypeInfo valueType) 40 | throws TypeException 41 | { 42 | type = tenv.get(nest, index); 43 | if (type == null) { 44 | type = valueType; 45 | tenv.put(0, index, valueType); 46 | return valueType; 47 | } 48 | else { 49 | valueType.assertSubtypeOf(type, tenv, this); 50 | return type; 51 | } 52 | } 53 | } 54 | @Reviser public static class NegativeEx extends NegativeExpr { 55 | public NegativeEx(List c) { super(c); } 56 | public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 57 | TypeInfo t = ((ASTreeTypeEx)operand()).typeCheck(tenv); 58 | t.assertSubtypeOf(TypeInfo.INT, tenv, this); 59 | return TypeInfo.INT; 60 | } 61 | } 62 | @Reviser public static class BinaryEx extends BinaryExpr { 63 | protected TypeInfo leftType, rightType; 64 | public BinaryEx(List c) { super(c); } 65 | public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 66 | String op = operator(); 67 | if ("=".equals(op)) 68 | return typeCheckForAssign(tenv); 69 | else { 70 | leftType = ((ASTreeTypeEx)left()).typeCheck(tenv); 71 | rightType = ((ASTreeTypeEx)right()).typeCheck(tenv); 72 | if ("+".equals(op)) 73 | return leftType.plus(rightType, tenv); 74 | else if ("==".equals(op)) 75 | return TypeInfo.INT; 76 | else { 77 | leftType.assertSubtypeOf(TypeInfo.INT, tenv, this); 78 | rightType.assertSubtypeOf(TypeInfo.INT, tenv, this); 79 | return TypeInfo.INT; 80 | } 81 | } 82 | } 83 | protected TypeInfo typeCheckForAssign(TypeEnv tenv) 84 | throws TypeException 85 | { 86 | rightType = ((ASTreeTypeEx)right()).typeCheck(tenv); 87 | ASTree le = left(); 88 | if (le instanceof Name) 89 | return ((NameEx2)le).typeCheckForAssign(tenv, rightType); 90 | else 91 | throw new TypeException("bad assignment", this); 92 | } 93 | } 94 | @Reviser public static class BlockEx extends BlockStmnt { 95 | TypeInfo type; 96 | public BlockEx(List c) { super(c); } 97 | public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 98 | type = TypeInfo.INT; 99 | for (ASTree t: this) 100 | if (!(t instanceof NullStmnt)) 101 | type = ((ASTreeTypeEx)t).typeCheck(tenv); 102 | return type; 103 | } 104 | } 105 | @Reviser public static class IfEx extends IfStmnt { 106 | public IfEx(List c) { super(c); } 107 | public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 108 | TypeInfo condType = ((ASTreeTypeEx)condition()).typeCheck(tenv); 109 | condType.assertSubtypeOf(TypeInfo.INT, tenv, this); 110 | TypeInfo thenType = ((ASTreeTypeEx)thenBlock()).typeCheck(tenv); 111 | TypeInfo elseType; 112 | ASTree elseBk = elseBlock(); 113 | if (elseBk == null) 114 | elseType = TypeInfo.INT; 115 | else 116 | elseType = ((ASTreeTypeEx)elseBk).typeCheck(tenv); 117 | return thenType.union(elseType, tenv); 118 | } 119 | } 120 | @Reviser public static class WhileEx extends WhileStmnt { 121 | public WhileEx(List c) { super(c); } 122 | public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 123 | TypeInfo condType = ((ASTreeTypeEx)condition()).typeCheck(tenv); 124 | condType.assertSubtypeOf(TypeInfo.INT, tenv, this); 125 | TypeInfo bodyType = ((ASTreeTypeEx)body()).typeCheck(tenv); 126 | return bodyType.union(TypeInfo.INT, tenv); 127 | } 128 | } 129 | @Reviser public static class DefStmntEx2 extends TypedEvaluator.DefStmntEx { 130 | protected TypeInfo.FunctionType funcType; 131 | protected TypeEnv bodyEnv; 132 | public DefStmntEx2(List c) { super(c); } 133 | public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 134 | TypeInfo[] params = ((ParamListEx2)parameters()).types(); 135 | TypeInfo retType = TypeInfo.get(type()); 136 | funcType = TypeInfo.function(retType, params); 137 | TypeInfo oldType = tenv.put(0, index, funcType); 138 | if (oldType != null) 139 | throw new TypeException("function redefinition: " + name(), 140 | this); 141 | bodyEnv = new TypeEnv(size, tenv); 142 | for (int i = 0; i < params.length; i++) 143 | bodyEnv.put(0, i, params[i]); 144 | TypeInfo bodyType 145 | = ((ASTreeTypeEx)revise(body())).typeCheck(bodyEnv); 146 | bodyType.assertSubtypeOf(retType, tenv, this); 147 | return funcType; 148 | } 149 | } 150 | @Reviser 151 | public static class ParamListEx2 extends TypedEvaluator.ParamListEx { 152 | public ParamListEx2(List c) { super(c); } 153 | public TypeInfo[] types() throws TypeException { 154 | int s = size(); 155 | TypeInfo[] result = new TypeInfo[s]; 156 | for (int i = 0; i < s; i++) 157 | result[i] = TypeInfo.get(typeTag(i)); 158 | return result; 159 | } 160 | } 161 | @Reviser public static class PrimaryEx2 extends FuncEvaluator.PrimaryEx { 162 | public PrimaryEx2(List c) { super(c); } 163 | public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 164 | return typeCheck(tenv, 0); 165 | } 166 | public TypeInfo typeCheck(TypeEnv tenv, int nest) throws TypeException { 167 | if (hasPostfix(nest)) { 168 | TypeInfo target = typeCheck(tenv, nest + 1); 169 | return ((PostfixEx)postfix(nest)).typeCheck(tenv, target); 170 | } 171 | else 172 | return ((ASTreeTypeEx)operand()).typeCheck(tenv); 173 | } 174 | } 175 | @Reviser public static abstract class PostfixEx extends Postfix { 176 | public PostfixEx(List c) { super(c); } 177 | public abstract TypeInfo typeCheck(TypeEnv tenv, TypeInfo target) 178 | throws TypeException; 179 | } 180 | @Reviser public static class ArgumentsEx extends Arguments { 181 | protected TypeInfo[] argTypes; 182 | protected TypeInfo.FunctionType funcType; 183 | public ArgumentsEx(List c) { super(c); } 184 | public TypeInfo typeCheck(TypeEnv tenv, TypeInfo target) 185 | throws TypeException 186 | { 187 | if (!(target instanceof TypeInfo.FunctionType)) 188 | throw new TypeException("bad function", this); 189 | funcType = (TypeInfo.FunctionType)target; 190 | TypeInfo[] params = funcType.parameterTypes; 191 | if (size() != params.length) 192 | throw new TypeException("bad number of arguments", this); 193 | argTypes = new TypeInfo[params.length]; 194 | int num = 0; 195 | for (ASTree a: this) { 196 | TypeInfo t = argTypes[num] = ((ASTreeTypeEx)a).typeCheck(tenv); 197 | t.assertSubtypeOf(params[num++], tenv, this); 198 | } 199 | return funcType.returnType; 200 | } 201 | } 202 | @Reviser public static class VarStmntEx2 extends TypedEvaluator.VarStmntEx { 203 | protected TypeInfo varType, valueType; 204 | public VarStmntEx2(List c) { super(c); } 205 | public TypeInfo typeCheck(TypeEnv tenv) throws TypeException { 206 | if (tenv.get(0, index) != null) 207 | throw new TypeException("duplicate variable: " + name(), this); 208 | varType = TypeInfo.get(type()); 209 | tenv.put(0, index, varType); 210 | valueType = ((ASTreeTypeEx)initializer()).typeCheck(tenv); 211 | valueType.assertSubtypeOf(varType, tenv, this); 212 | return varType; 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/chap14/TypeEnv.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import java.util.Arrays; 3 | import stone.StoneException; 4 | 5 | public class TypeEnv { 6 | protected TypeEnv outer; 7 | protected TypeInfo[] types; 8 | public TypeEnv() { this(8, null); } 9 | public TypeEnv(int size, TypeEnv out) { 10 | outer = out; 11 | types = new TypeInfo[size]; 12 | } 13 | public TypeInfo get(int nest, int index) { 14 | if (nest == 0) 15 | if (index < types.length) 16 | return types[index]; 17 | else 18 | return null; 19 | else if (outer == null) 20 | return null; 21 | else 22 | return outer.get(nest - 1, index); 23 | } 24 | public TypeInfo put(int nest, int index, TypeInfo value) { 25 | TypeInfo oldValue; 26 | if (nest == 0) { 27 | access(index); 28 | oldValue = types[index]; 29 | types[index] = value; 30 | return oldValue; // may be null 31 | } 32 | else if (outer == null) 33 | throw new StoneException("no outer type environment"); 34 | else 35 | return outer.put(nest - 1, index, value); 36 | } 37 | protected void access(int index) { 38 | if (index >= types.length) { 39 | int newLen = types.length * 2; 40 | if (index >= newLen) 41 | newLen = index + 1; 42 | types = Arrays.copyOf(types, newLen); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/chap14/TypeException.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import stone.ast.ASTree; 3 | 4 | public class TypeException extends Exception { 5 | public TypeException(String msg, ASTree t) { 6 | super(msg + " " + t.location()); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/chap14/TypeInfo.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | 3 | import stone.ast.ASTree; 4 | import stone.ast.TypeTag; 5 | 6 | public class TypeInfo { 7 | public static final TypeInfo ANY = new TypeInfo() { 8 | @Override public String toString() { return "Any"; } 9 | }; 10 | public static final TypeInfo INT = new TypeInfo() { 11 | @Override public String toString() { return "Int"; } 12 | }; 13 | public static final TypeInfo STRING = new TypeInfo() { 14 | @Override public String toString() { return "String"; } 15 | }; 16 | 17 | public TypeInfo type() { return this; } 18 | public boolean match(TypeInfo obj) { 19 | return type() == obj.type(); 20 | } 21 | public boolean subtypeOf(TypeInfo superType) { 22 | superType = superType.type(); 23 | return type() == superType || superType == ANY; 24 | } 25 | public void assertSubtypeOf(TypeInfo type, TypeEnv env, ASTree where) 26 | throws TypeException 27 | { 28 | if (!subtypeOf(type)) 29 | throw new TypeException("type mismatch: cannot convert from " 30 | + this + " to " + type, where); 31 | } 32 | public TypeInfo union(TypeInfo right, TypeEnv tenv) { 33 | if (match(right)) 34 | return type(); 35 | else 36 | return ANY; 37 | } 38 | public TypeInfo plus(TypeInfo right, TypeEnv tenv) { 39 | if (INT.match(this) && INT.match(right)) 40 | return INT; 41 | else if (STRING.match(this) || STRING.match(right)) 42 | return STRING; 43 | else 44 | return ANY; 45 | } 46 | public static TypeInfo get(TypeTag tag) throws TypeException { 47 | String tname = tag.type(); 48 | if (INT.toString().equals(tname)) 49 | return INT; 50 | else if (STRING.toString().equals(tname)) 51 | return STRING; 52 | else if (ANY.toString().equals(tname)) 53 | return ANY; 54 | else if (TypeTag.UNDEF.equals(tname)) 55 | return new UnknownType(); 56 | else 57 | throw new TypeException("unknown type " + tname, tag); 58 | } 59 | public static FunctionType function(TypeInfo ret, TypeInfo... params) { 60 | return new FunctionType(ret, params); 61 | } 62 | public boolean isFunctionType() { return false; } 63 | public FunctionType toFunctionType() { return null; } 64 | public boolean isUnknownType() { return false; } 65 | public UnknownType toUnknownType() { return null; } 66 | public static class UnknownType extends TypeInfo { 67 | @Override public TypeInfo type() { return ANY; } 68 | @Override public String toString() { return type().toString(); } 69 | @Override public boolean isUnknownType() { return true; } 70 | @Override public UnknownType toUnknownType() { return this; } 71 | } 72 | public static class FunctionType extends TypeInfo { 73 | public TypeInfo returnType; 74 | public TypeInfo[] parameterTypes; 75 | public FunctionType(TypeInfo ret, TypeInfo... params) { 76 | returnType = ret; 77 | parameterTypes = params; 78 | } 79 | @Override public boolean isFunctionType() { return true; } 80 | @Override public FunctionType toFunctionType() { return this; } 81 | @Override public boolean match(TypeInfo obj) { 82 | if (!(obj instanceof FunctionType)) 83 | return false; 84 | FunctionType func = (FunctionType)obj; 85 | if (parameterTypes.length != func.parameterTypes.length) 86 | return false; 87 | for (int i = 0; i < parameterTypes.length; i++) 88 | if (!parameterTypes[i].match(func.parameterTypes[i])) 89 | return false; 90 | return returnType.match(func.returnType); 91 | } 92 | @Override public String toString() { 93 | StringBuilder sb = new StringBuilder(); 94 | if (parameterTypes.length == 0) 95 | sb.append("Unit"); 96 | else 97 | for (int i = 0; i < parameterTypes.length; i++) { 98 | if (i > 0) 99 | sb.append(" * "); 100 | sb.append(parameterTypes[i]); 101 | } 102 | sb.append(" -> ").append(returnType); 103 | return sb.toString(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/chap14/TypedEvaluator.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import java.util.List; 3 | import javassist.gluonj.*; 4 | import stone.ast.*; 5 | import chap11.EnvOptimizer; 6 | import chap11.Symbols; 7 | import chap11.EnvOptimizer.ASTreeOptEx; 8 | import chap6.Environment; 9 | import chap6.BasicEvaluator.ASTreeEx; 10 | 11 | @Require(EnvOptimizer.class) 12 | @Reviser public class TypedEvaluator { 13 | @Reviser public static class DefStmntEx extends EnvOptimizer.DefStmntEx { 14 | public DefStmntEx(List c) { super(c); } 15 | public TypeTag type() { return (TypeTag)child(2); } 16 | @Override public BlockStmnt body() { return (BlockStmnt)child(3); } 17 | @Override public String toString() { 18 | return "(def " + name() + " " + parameters() + " " + type() + " " 19 | + body() + ")"; 20 | } 21 | } 22 | @Reviser public static class ParamListEx extends EnvOptimizer.ParamsEx { 23 | public ParamListEx(List c) { super(c); } 24 | @Override public String name(int i) { 25 | return ((ASTLeaf)child(i).child(0)).token().getText(); 26 | } 27 | public TypeTag typeTag(int i) { 28 | return (TypeTag)child(i).child(1); 29 | } 30 | } 31 | @Reviser public static class VarStmntEx extends VarStmnt { 32 | protected int index; 33 | public VarStmntEx(List c) { super(c); } 34 | public void lookup(Symbols syms) { 35 | index = syms.putNew(name()); 36 | ((ASTreeOptEx)initializer()).lookup(syms); 37 | } 38 | public Object eval(Environment env) { 39 | Object value = ((ASTreeEx)initializer()).eval(env); 40 | ((EnvOptimizer.EnvEx2)env).put(0, index, value); 41 | return value; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/chap14/TypedInterpreter.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import stone.BasicParser; 3 | import stone.CodeDialog; 4 | import stone.Lexer; 5 | import stone.Token; 6 | import stone.TypedParser; 7 | import stone.ParseException; 8 | import stone.ast.ASTree; 9 | import stone.ast.NullStmnt; 10 | import chap11.EnvOptimizer; 11 | import chap11.ResizableArrayEnv; 12 | import chap6.BasicEvaluator; 13 | import chap6.Environment; 14 | 15 | public class TypedInterpreter { 16 | public static void main(String[] args) throws ParseException, TypeException { 17 | TypeEnv te = new TypeEnv(); 18 | run(new TypedParser(), 19 | new TypedNatives(te).environment(new ResizableArrayEnv()), 20 | te); 21 | } 22 | public static void run(BasicParser bp, Environment env, TypeEnv typeEnv) 23 | throws ParseException, TypeException 24 | { 25 | Lexer lexer = new Lexer(new CodeDialog()); 26 | while (lexer.peek(0) != Token.EOF) { 27 | ASTree tree = bp.parse(lexer); 28 | if (!(tree instanceof NullStmnt)) { 29 | ((EnvOptimizer.ASTreeOptEx)tree).lookup( 30 | ((EnvOptimizer.EnvEx2)env).symbols()); 31 | TypeInfo type 32 | = ((TypeChecker.ASTreeTypeEx)tree).typeCheck(typeEnv); 33 | Object r = ((BasicEvaluator.ASTreeEx)tree).eval(env); 34 | System.out.println("=> " + r + " : " + type); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/chap14/TypedNatives.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import chap6.Environment; 3 | import chap8.Natives; 4 | import chap11.EnvOptimizer.EnvEx2; 5 | 6 | public class TypedNatives extends Natives { 7 | protected TypeEnv typeEnv; 8 | public TypedNatives(TypeEnv te) { typeEnv = te; } 9 | protected void append(Environment env, String name, Class clazz, 10 | String methodName, TypeInfo type, Class ... params) 11 | { 12 | append(env, name, clazz, methodName, params); 13 | int index = ((EnvEx2)env).symbols().find(name); 14 | typeEnv.put(0, index, type); 15 | } 16 | protected void appendNatives(Environment env) { 17 | append(env, "print", chap14.java.print.class, "m", 18 | TypeInfo.function(TypeInfo.INT, TypeInfo.ANY), 19 | Object.class); 20 | append(env, "read", chap14.java.read.class, "m", 21 | TypeInfo.function(TypeInfo.STRING)); 22 | append(env, "length", chap14.java.length.class, "m", 23 | TypeInfo.function(TypeInfo.INT, TypeInfo.STRING), 24 | String.class); 25 | append(env, "toInt", chap14.java.toInt.class, "m", 26 | TypeInfo.function(TypeInfo.INT, TypeInfo.ANY), 27 | Object.class); 28 | append(env, "currentTime", chap14.java.currentTime.class, "m", 29 | TypeInfo.function(TypeInfo.INT)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/chap14/TypedRunner.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | import javassist.gluonj.util.Loader; 3 | import chap8.NativeEvaluator; 4 | 5 | public class TypedRunner { 6 | public static void main(String[] args) throws Throwable { 7 | Loader.run(TypedInterpreter.class, args, TypeChecker.class, 8 | NativeEvaluator.class); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/chap14/java/currentTime.java: -------------------------------------------------------------------------------- 1 | package chap14.java; 2 | import chap11.ArrayEnv; 3 | 4 | public class currentTime { 5 | private static long startTime = System.currentTimeMillis(); 6 | public static int m(ArrayEnv env) { return m(); } 7 | public static int m() { 8 | return (int)(System.currentTimeMillis() - startTime); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/chap14/java/length.java: -------------------------------------------------------------------------------- 1 | package chap14.java; 2 | import chap11.ArrayEnv; 3 | 4 | public class length { 5 | public static int m(ArrayEnv env, String s) { return m(s); } 6 | public static int m(String s) { return s.length(); } 7 | } 8 | -------------------------------------------------------------------------------- /src/chap14/java/print.java: -------------------------------------------------------------------------------- 1 | package chap14.java; 2 | import chap11.ArrayEnv; 3 | 4 | public class print { 5 | public static int m(ArrayEnv env, Object obj) { return m(obj); } 6 | public static int m(Object obj) { 7 | System.out.println(obj.toString()); 8 | return 0; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/chap14/java/read.java: -------------------------------------------------------------------------------- 1 | package chap14.java; 2 | import chap11.ArrayEnv; 3 | import javax.swing.JOptionPane; 4 | 5 | public class read { 6 | public static String m(ArrayEnv env) { return m(); } 7 | public static String m() { 8 | return JOptionPane.showInputDialog(null); 9 | } 10 | } -------------------------------------------------------------------------------- /src/chap14/java/toInt.java: -------------------------------------------------------------------------------- 1 | package chap14.java; 2 | import chap11.ArrayEnv; 3 | 4 | public class toInt { 5 | public static int m(ArrayEnv env, Object value) { return m(value); } 6 | public static int m(Object value) { 7 | if (value instanceof String) 8 | return Integer.parseInt((String)value); 9 | else if (value instanceof Integer) 10 | return ((Integer)value).intValue(); 11 | else 12 | throw new NumberFormatException(value.toString()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/chap3/FileLexerRunner.java: -------------------------------------------------------------------------------- 1 | package chap3; 2 | import stone.*; 3 | import java.io.FileNotFoundException; 4 | 5 | public class FileLexerRunner { 6 | public static void main(String[] args) throws ParseException { 7 | try { 8 | Lexer l = new Lexer(CodeDialog.file()); 9 | for (Token t; (t = l.read()) != Token.EOF; ) 10 | System.out.println("=> " + t.getText()); 11 | } 12 | catch(FileNotFoundException e) { 13 | System.out.println(e.getMessage()); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/chap3/LexerRunner.java: -------------------------------------------------------------------------------- 1 | package chap3; 2 | import stone.*; 3 | 4 | public class LexerRunner { 5 | public static void main(String[] args) throws ParseException { 6 | Lexer l = new Lexer(new CodeDialog()); 7 | for (Token t; (t = l.read()) != Token.EOF; ) 8 | System.out.println("=> " + t.getText()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/chap5/ParserRunner.java: -------------------------------------------------------------------------------- 1 | package chap5; 2 | import stone.ast.ASTree; 3 | import stone.*; 4 | 5 | public class ParserRunner { 6 | public static void main(String[] args) throws ParseException { 7 | Lexer l = new Lexer(new CodeDialog()); 8 | BasicParser bp = new BasicParser(); 9 | while (l.peek(0) != Token.EOF) { 10 | ASTree ast = bp.parse(l); 11 | System.out.println("=> " + ast.toString()); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/chap6/BasicEnv.java: -------------------------------------------------------------------------------- 1 | package chap6; 2 | import java.util.HashMap; 3 | 4 | public class BasicEnv implements Environment { 5 | protected HashMap values; 6 | public BasicEnv() { values = new HashMap(); } 7 | public void put(String name, Object value) { values.put(name, value); } 8 | public Object get(String name) { return values.get(name); } 9 | } 10 | -------------------------------------------------------------------------------- /src/chap6/BasicEvaluator.java: -------------------------------------------------------------------------------- 1 | package chap6; 2 | import javassist.gluonj.*; 3 | import stone.Token; 4 | import stone.StoneException; 5 | import stone.ast.*; 6 | import java.util.List; 7 | 8 | @Reviser public class BasicEvaluator { 9 | public static final int TRUE = 1; 10 | public static final int FALSE = 0; 11 | @Reviser public static abstract class ASTreeEx extends ASTree { 12 | public abstract Object eval(Environment env); 13 | } 14 | @Reviser public static class ASTListEx extends ASTList { 15 | public ASTListEx(List c) { super(c); } 16 | public Object eval(Environment env) { 17 | throw new StoneException("cannot eval: " + toString(), this); 18 | } 19 | } 20 | @Reviser public static class ASTLeafEx extends ASTLeaf { 21 | public ASTLeafEx(Token t) { super(t); } 22 | public Object eval(Environment env) { 23 | throw new StoneException("cannot eval: " + toString(), this); 24 | } 25 | } 26 | @Reviser public static class NumberEx extends NumberLiteral { 27 | public NumberEx(Token t) { super(t); } 28 | public Object eval(Environment e) { return value(); } 29 | } 30 | @Reviser public static class StringEx extends StringLiteral { 31 | public StringEx(Token t) { super(t); } 32 | public Object eval(Environment e) { return value(); } 33 | } 34 | @Reviser public static class NameEx extends Name { 35 | public NameEx(Token t) { super(t); } 36 | public Object eval(Environment env) { 37 | Object value = env.get(name()); 38 | if (value == null) 39 | throw new StoneException("undefined name: " + name(), this); 40 | else 41 | return value; 42 | } 43 | } 44 | @Reviser public static class NegativeEx extends NegativeExpr { 45 | public NegativeEx(List c) { super(c); } 46 | public Object eval(Environment env) { 47 | Object v = ((ASTreeEx)operand()).eval(env); 48 | if (v instanceof Integer) 49 | return Integer.valueOf(-((Integer)v).intValue()); 50 | else 51 | throw new StoneException("bad type for -", this); 52 | } 53 | } 54 | @Reviser public static class BinaryEx extends BinaryExpr { 55 | public BinaryEx(List c) { super(c); } 56 | public Object eval(Environment env) { 57 | String op = operator(); 58 | if ("=".equals(op)) { 59 | Object right = ((ASTreeEx)right()).eval(env); 60 | return computeAssign(env, right); 61 | } 62 | else { 63 | Object left = ((ASTreeEx)left()).eval(env); 64 | Object right = ((ASTreeEx)right()).eval(env); 65 | return computeOp(left, op, right); 66 | } 67 | } 68 | protected Object computeAssign(Environment env, Object rvalue) { 69 | ASTree l = left(); 70 | if (l instanceof Name) { 71 | env.put(((Name)l).name(), rvalue); 72 | return rvalue; 73 | } 74 | else 75 | throw new StoneException("bad assignment", this); 76 | } 77 | protected Object computeOp(Object left, String op, Object right) { 78 | if (left instanceof Integer && right instanceof Integer) { 79 | return computeNumber((Integer)left, op, (Integer)right); 80 | } 81 | else 82 | if (op.equals("+")) 83 | return String.valueOf(left) + String.valueOf(right); 84 | else if (op.equals("==")) { 85 | if (left == null) 86 | return right == null ? TRUE : FALSE; 87 | else 88 | return left.equals(right) ? TRUE : FALSE; 89 | } 90 | else 91 | throw new StoneException("bad type", this); 92 | } 93 | protected Object computeNumber(Integer left, String op, Integer right) { 94 | int a = left.intValue(); 95 | int b = right.intValue(); 96 | if (op.equals("+")) 97 | return a + b; 98 | else if (op.equals("-")) 99 | return a - b; 100 | else if (op.equals("*")) 101 | return a * b; 102 | else if (op.equals("/")) 103 | return a / b; 104 | else if (op.equals("%")) 105 | return a % b; 106 | else if (op.equals("==")) 107 | return a == b ? TRUE : FALSE; 108 | else if (op.equals(">")) 109 | return a > b ? TRUE : FALSE; 110 | else if (op.equals("<")) 111 | return a < b ? TRUE : FALSE; 112 | else 113 | throw new StoneException("bad operator", this); 114 | } 115 | } 116 | @Reviser public static class BlockEx extends BlockStmnt { 117 | public BlockEx(List c) { super(c); } 118 | public Object eval(Environment env) { 119 | Object result = 0; 120 | for (ASTree t: this) { 121 | if (!(t instanceof NullStmnt)) 122 | result = ((ASTreeEx)t).eval(env); 123 | } 124 | return result; 125 | } 126 | } 127 | @Reviser public static class IfEx extends IfStmnt { 128 | public IfEx(List c) { super(c); } 129 | public Object eval(Environment env) { 130 | Object c = ((ASTreeEx)condition()).eval(env); 131 | if (c instanceof Integer && ((Integer)c).intValue() != FALSE) 132 | return ((ASTreeEx)thenBlock()).eval(env); 133 | else { 134 | ASTree b = elseBlock(); 135 | if (b == null) 136 | return 0; 137 | else 138 | return ((ASTreeEx)b).eval(env); 139 | } 140 | } 141 | } 142 | @Reviser public static class WhileEx extends WhileStmnt { 143 | public WhileEx(List c) { super(c); } 144 | public Object eval(Environment env) { 145 | Object result = 0; 146 | for (;;) { 147 | Object c = ((ASTreeEx)condition()).eval(env); 148 | if (c instanceof Integer && ((Integer)c).intValue() == FALSE) 149 | return result; 150 | else 151 | result = ((ASTreeEx)body()).eval(env); 152 | } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/chap6/BasicFileInterpreter.java: -------------------------------------------------------------------------------- 1 | package chap6; 2 | import stone.*; 3 | import stone.ast.ASTree; 4 | import stone.ast.NullStmnt; 5 | import java.io.FileReader; 6 | import java.io.FileNotFoundException; 7 | 8 | public class BasicFileInterpreter { 9 | public static void main(String[] args) 10 | throws ParseException, FileNotFoundException 11 | { 12 | run(new BasicParser(), new BasicEnv(), args[0]); 13 | } 14 | 15 | public static void run(BasicParser bp, Environment env, String fileName) 16 | throws ParseException, FileNotFoundException 17 | { 18 | FileReader reader = new FileReader(fileName); 19 | Lexer lexer = new Lexer(reader); 20 | while (lexer.peek(0) != Token.EOF) { 21 | ASTree t = bp.parse(lexer); 22 | if (!(t instanceof NullStmnt)) { 23 | Object r = ((BasicEvaluator.ASTreeEx)t).eval(env); 24 | System.out.println("=> " + r); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/chap6/BasicInterpreter.java: -------------------------------------------------------------------------------- 1 | package chap6; 2 | import stone.*; 3 | import stone.ast.ASTree; 4 | import stone.ast.NullStmnt; 5 | 6 | public class BasicInterpreter { 7 | public static void main(String[] args) throws ParseException { 8 | run(new BasicParser(), new BasicEnv()); 9 | } 10 | public static void run(BasicParser bp, Environment env) 11 | throws ParseException 12 | { 13 | Lexer lexer = new Lexer(new CodeDialog()); 14 | while (lexer.peek(0) != Token.EOF) { 15 | ASTree t = bp.parse(lexer); 16 | if (!(t instanceof NullStmnt)) { 17 | Object r = ((BasicEvaluator.ASTreeEx)t).eval(env); 18 | System.out.println("=> " + r); 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/chap6/Environment.java: -------------------------------------------------------------------------------- 1 | package chap6; 2 | 3 | public interface Environment { 4 | void put(String name, Object value); 5 | Object get(String name); 6 | } 7 | -------------------------------------------------------------------------------- /src/chap6/FileRunner.java: -------------------------------------------------------------------------------- 1 | package chap6; 2 | import javassist.gluonj.util.Loader; 3 | 4 | // To run, 5 | // java -cp ./bin:gluonj.jar chap6.FileRunner src/chap6/sum.stone 6 | 7 | public class FileRunner { 8 | public static void main(String[] args) throws Throwable { 9 | Loader.run(BasicFileInterpreter.class, args, BasicEvaluator.class); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/chap6/Runner.java: -------------------------------------------------------------------------------- 1 | package chap6; 2 | import javassist.gluonj.util.Loader; 3 | 4 | public class Runner { 5 | public static void main(String[] args) throws Throwable { 6 | Loader.run(BasicInterpreter.class, args, BasicEvaluator.class); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/chap6/sum.stone: -------------------------------------------------------------------------------- 1 | sum = 0 2 | i = 1 3 | while i < 10 { 4 | sum = sum + 1 5 | i = i + 1 6 | } 7 | sum 8 | -------------------------------------------------------------------------------- /src/chap7/ClosureEvaluator.java: -------------------------------------------------------------------------------- 1 | package chap7; 2 | import java.util.List; 3 | import javassist.gluonj.*; 4 | import stone.ast.ASTree; 5 | import stone.ast.Fun; 6 | import chap6.Environment; 7 | 8 | @Require(FuncEvaluator.class) 9 | @Reviser public class ClosureEvaluator { 10 | @Reviser public static class FunEx extends Fun { 11 | public FunEx(List c) { super(c); } 12 | public Object eval(Environment env) { 13 | return new Function(parameters(), body(), env); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/chap7/ClosureInterpreter.java: -------------------------------------------------------------------------------- 1 | package chap7; 2 | import stone.ClosureParser; 3 | import stone.ParseException; 4 | import chap6.BasicInterpreter; 5 | 6 | public class ClosureInterpreter extends BasicInterpreter{ 7 | public static void main(String[] args) throws ParseException { 8 | run(new ClosureParser(), new NestedEnv()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/chap7/ClosureRunner.java: -------------------------------------------------------------------------------- 1 | package chap7; 2 | import javassist.gluonj.util.Loader; 3 | 4 | public class ClosureRunner { 5 | public static void main(String[] args) throws Throwable { 6 | Loader.run(ClosureInterpreter.class, args, ClosureEvaluator.class); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/chap7/FuncEvaluator.java: -------------------------------------------------------------------------------- 1 | package chap7; 2 | import java.util.List; 3 | import javassist.gluonj.*; 4 | import stone.StoneException; 5 | import stone.ast.*; 6 | import chap6.BasicEvaluator; 7 | import chap6.Environment; 8 | import chap6.BasicEvaluator.ASTreeEx; 9 | import chap6.BasicEvaluator.BlockEx; 10 | 11 | @Require(BasicEvaluator.class) 12 | @Reviser public class FuncEvaluator { 13 | @Reviser public static interface EnvEx extends Environment { 14 | void putNew(String name, Object value); 15 | Environment where(String name); 16 | void setOuter(Environment e); 17 | } 18 | @Reviser public static class DefStmntEx extends DefStmnt { 19 | public DefStmntEx(List c) { super(c); } 20 | public Object eval(Environment env) { 21 | ((EnvEx)env).putNew(name(), new Function(parameters(), body(), env)); 22 | return name(); 23 | } 24 | } 25 | @Reviser public static class PrimaryEx extends PrimaryExpr { 26 | public PrimaryEx(List c) { super(c); } 27 | public ASTree operand() { return child(0); } 28 | public Postfix postfix(int nest) { 29 | return (Postfix)child(numChildren() - nest - 1); 30 | } 31 | public boolean hasPostfix(int nest) { return numChildren() - nest > 1; } 32 | public Object eval(Environment env) { 33 | return evalSubExpr(env, 0); 34 | } 35 | public Object evalSubExpr(Environment env, int nest) { 36 | if (hasPostfix(nest)) { 37 | Object target = evalSubExpr(env, nest + 1); 38 | return ((PostfixEx)postfix(nest)).eval(env, target); 39 | } 40 | else 41 | return ((ASTreeEx)operand()).eval(env); 42 | } 43 | } 44 | @Reviser public static abstract class PostfixEx extends Postfix { 45 | public PostfixEx(List c) { super(c); } 46 | public abstract Object eval(Environment env, Object value); 47 | } 48 | @Reviser public static class ArgumentsEx extends Arguments { 49 | public ArgumentsEx(List c) { super(c); } 50 | public Object eval(Environment callerEnv, Object value) { 51 | if (!(value instanceof Function)) 52 | throw new StoneException("bad function", this); 53 | Function func = (Function)value; 54 | ParameterList params = func.parameters(); 55 | if (size() != params.size()) 56 | throw new StoneException("bad number of arguments", this); 57 | Environment newEnv = func.makeEnv(); 58 | int num = 0; 59 | for (ASTree a: this) 60 | ((ParamsEx)params).eval(newEnv, num++, 61 | ((ASTreeEx)a).eval(callerEnv)); 62 | return ((BlockEx)func.body()).eval(newEnv); 63 | } 64 | } 65 | @Reviser public static class ParamsEx extends ParameterList { 66 | public ParamsEx(List c) { super(c); } 67 | public void eval(Environment env, int index, Object value) { 68 | ((EnvEx)env).putNew(name(index), value); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/chap7/FuncInterpreter.java: -------------------------------------------------------------------------------- 1 | package chap7; 2 | import stone.FuncParser; 3 | import stone.ParseException; 4 | import chap6.BasicInterpreter; 5 | 6 | public class FuncInterpreter extends BasicInterpreter { 7 | public static void main(String[] args) throws ParseException { 8 | run(new FuncParser(), new NestedEnv()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/chap7/FuncRunner.java: -------------------------------------------------------------------------------- 1 | package chap7; 2 | import javassist.gluonj.util.Loader; 3 | 4 | public class FuncRunner { 5 | public static void main(String[] args) throws Throwable { 6 | Loader.run(FuncInterpreter.class, args, FuncEvaluator.class); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/chap7/Function.java: -------------------------------------------------------------------------------- 1 | package chap7; 2 | import stone.ast.BlockStmnt; 3 | import stone.ast.ParameterList; 4 | import chap6.Environment; 5 | 6 | public class Function { 7 | protected ParameterList parameters; 8 | protected BlockStmnt body; 9 | protected Environment env; 10 | public Function(ParameterList parameters, BlockStmnt body, Environment env) { 11 | this.parameters = parameters; 12 | this.body = body; 13 | this.env = env; 14 | } 15 | public ParameterList parameters() { return parameters; } 16 | public BlockStmnt body() { return body; } 17 | public Environment makeEnv() { return new NestedEnv(env); } 18 | @Override public String toString() { return ""; } 19 | } 20 | -------------------------------------------------------------------------------- /src/chap7/NestedEnv.java: -------------------------------------------------------------------------------- 1 | package chap7; 2 | import java.util.HashMap; 3 | import chap6.Environment; 4 | import chap7.FuncEvaluator.EnvEx; 5 | 6 | public class NestedEnv implements Environment { 7 | protected HashMap values; 8 | protected Environment outer; 9 | public NestedEnv() { this(null); } 10 | public NestedEnv(Environment e) { 11 | values = new HashMap(); 12 | outer = e; 13 | } 14 | public void setOuter(Environment e) { outer = e; } 15 | public Object get(String name) { 16 | Object v = values.get(name); 17 | if (v == null && outer != null) 18 | return outer.get(name); 19 | else 20 | return v; 21 | } 22 | public void putNew(String name, Object value) { values.put(name, value); } 23 | public void put(String name, Object value) { 24 | Environment e = where(name); 25 | if (e == null) 26 | e = this; 27 | ((EnvEx)e).putNew(name, value); 28 | } 29 | public Environment where(String name) { 30 | if (values.get(name) != null) 31 | return this; 32 | else if (outer == null) 33 | return null; 34 | else 35 | return ((EnvEx)outer).where(name); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/chap8/NativeEvaluator.java: -------------------------------------------------------------------------------- 1 | package chap8; 2 | import java.util.List; 3 | import stone.StoneException; 4 | import stone.ast.ASTree; 5 | import javassist.gluonj.*; 6 | import chap6.Environment; 7 | import chap6.BasicEvaluator.ASTreeEx; 8 | import chap7.FuncEvaluator; 9 | 10 | @Require(FuncEvaluator.class) 11 | @Reviser public class NativeEvaluator { 12 | @Reviser public static class NativeArgEx extends FuncEvaluator.ArgumentsEx { 13 | public NativeArgEx(List c) { super(c); } 14 | @Override public Object eval(Environment callerEnv, Object value) { 15 | if (!(value instanceof NativeFunction)) 16 | return super.eval(callerEnv, value); 17 | 18 | NativeFunction func = (NativeFunction)value; 19 | int nparams = func.numOfParameters(); 20 | if (size() != nparams) 21 | throw new StoneException("bad number of arguments", this); 22 | Object[] args = new Object[nparams]; 23 | int num = 0; 24 | for (ASTree a: this) { 25 | ASTreeEx ae = (ASTreeEx)a; 26 | args[num++] = ae.eval(callerEnv); 27 | } 28 | return func.invoke(args, this); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/chap8/NativeFunction.java: -------------------------------------------------------------------------------- 1 | package chap8; 2 | import java.lang.reflect.Method; 3 | import stone.StoneException; 4 | import stone.ast.ASTree; 5 | 6 | public class NativeFunction { 7 | protected Method method; 8 | protected String name; 9 | protected int numParams; 10 | public NativeFunction(String n, Method m) { 11 | name = n; 12 | method = m; 13 | numParams = m.getParameterTypes().length; 14 | } 15 | @Override public String toString() { return ""; } 16 | public int numOfParameters() { return numParams; } 17 | public Object invoke(Object[] args, ASTree tree) { 18 | try { 19 | return method.invoke(null, args); 20 | } catch (Exception e) { 21 | throw new StoneException("bad native function call: " + name, tree); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/chap8/NativeInterpreter.java: -------------------------------------------------------------------------------- 1 | package chap8; 2 | import stone.ClosureParser; 3 | import stone.ParseException; 4 | import chap6.BasicInterpreter; 5 | import chap7.NestedEnv; 6 | 7 | public class NativeInterpreter extends BasicInterpreter { 8 | public static void main(String[] args) throws ParseException { 9 | run(new ClosureParser(), 10 | new Natives().environment(new NestedEnv())); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/chap8/NativeRunner.java: -------------------------------------------------------------------------------- 1 | package chap8; 2 | import javassist.gluonj.util.Loader; 3 | import chap7.ClosureEvaluator; 4 | 5 | public class NativeRunner { 6 | public static void main(String[] args) throws Throwable { 7 | Loader.run(NativeInterpreter.class, args, NativeEvaluator.class, 8 | ClosureEvaluator.class); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/chap8/Natives.java: -------------------------------------------------------------------------------- 1 | package chap8; 2 | import java.lang.reflect.Method; 3 | import javax.swing.JOptionPane; 4 | import stone.StoneException; 5 | import chap6.Environment; 6 | 7 | public class Natives { 8 | public Environment environment(Environment env) { 9 | appendNatives(env); 10 | return env; 11 | } 12 | protected void appendNatives(Environment env) { 13 | append(env, "print", Natives.class, "print", Object.class); 14 | append(env, "read", Natives.class, "read"); 15 | append(env, "length", Natives.class, "length", String.class); 16 | append(env, "toInt", Natives.class, "toInt", Object.class); 17 | append(env, "currentTime", Natives.class, "currentTime"); 18 | } 19 | protected void append(Environment env, String name, Class clazz, 20 | String methodName, Class ... params) { 21 | Method m; 22 | try { 23 | m = clazz.getMethod(methodName, params); 24 | } catch (Exception e) { 25 | throw new StoneException("cannot find a native function: " 26 | + methodName); 27 | } 28 | env.put(name, new NativeFunction(methodName, m)); 29 | } 30 | 31 | // native methods 32 | public static int print(Object obj) { 33 | System.out.println(obj.toString()); 34 | return 0; 35 | } 36 | public static String read() { 37 | return JOptionPane.showInputDialog(null); 38 | } 39 | public static int length(String s) { return s.length(); } 40 | public static int toInt(Object value) { 41 | if (value instanceof String) 42 | return Integer.parseInt((String)value); 43 | else if (value instanceof Integer) 44 | return ((Integer)value).intValue(); 45 | else 46 | throw new NumberFormatException(value.toString()); 47 | } 48 | private static long startTime = System.currentTimeMillis(); 49 | public static int currentTime() { 50 | return (int)(System.currentTimeMillis() - startTime); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/chap9/ClassEvaluator.java: -------------------------------------------------------------------------------- 1 | package chap9; 2 | import java.util.List; 3 | import stone.StoneException; 4 | import javassist.gluonj.*; 5 | import stone.ast.*; 6 | import chap6.Environment; 7 | import chap6.BasicEvaluator.ASTreeEx; 8 | import chap6.BasicEvaluator; 9 | import chap7.FuncEvaluator; 10 | import chap7.NestedEnv; 11 | import chap7.FuncEvaluator.EnvEx; 12 | import chap7.FuncEvaluator.PrimaryEx; 13 | import chap9.StoneObject.AccessException; 14 | 15 | @Require(FuncEvaluator.class) 16 | @Reviser public class ClassEvaluator { 17 | @Reviser public static class ClassStmntEx extends ClassStmnt { 18 | public ClassStmntEx(List c) { super(c); } 19 | public Object eval(Environment env) { 20 | ClassInfo ci = new ClassInfo(this, env); 21 | ((EnvEx)env).put(name(), ci); 22 | return name(); 23 | } 24 | } 25 | @Reviser public static class ClassBodyEx extends ClassBody { 26 | public ClassBodyEx(List c) { super(c); } 27 | public Object eval(Environment env) { 28 | for (ASTree t: this) 29 | ((ASTreeEx)t).eval(env); 30 | return null; 31 | } 32 | } 33 | @Reviser public static class DotEx extends Dot { 34 | public DotEx(List c) { super(c); } 35 | public Object eval(Environment env, Object value) { 36 | String member = name(); 37 | if (value instanceof ClassInfo) { 38 | if ("new".equals(member)) { 39 | ClassInfo ci = (ClassInfo)value; 40 | NestedEnv e = new NestedEnv(ci.environment()); 41 | StoneObject so = new StoneObject(e); 42 | e.putNew("this", so); 43 | initObject(ci, e); 44 | return so; 45 | } 46 | } 47 | else if (value instanceof StoneObject) { 48 | try { 49 | return ((StoneObject)value).read(member); 50 | } catch (AccessException e) {} 51 | } 52 | throw new StoneException("bad member access: " + member, this); 53 | } 54 | protected void initObject(ClassInfo ci, Environment env) { 55 | if (ci.superClass() != null) 56 | initObject(ci.superClass(), env); 57 | ((ClassBodyEx)ci.body()).eval(env); 58 | } 59 | } 60 | @Reviser public static class AssignEx extends BasicEvaluator.BinaryEx { 61 | public AssignEx(List c) { super(c); } 62 | @Override 63 | protected Object computeAssign(Environment env, Object rvalue) { 64 | ASTree le = left(); 65 | if (le instanceof PrimaryExpr) { 66 | PrimaryEx p = (PrimaryEx)le; 67 | if (p.hasPostfix(0) && p.postfix(0) instanceof Dot) { 68 | Object t = ((PrimaryEx)le).evalSubExpr(env, 1); 69 | if (t instanceof StoneObject) 70 | return setField((StoneObject)t, (Dot)p.postfix(0), 71 | rvalue); 72 | } 73 | } 74 | return super.computeAssign(env, rvalue); 75 | } 76 | protected Object setField(StoneObject obj, Dot expr, Object rvalue) { 77 | String name = expr.name(); 78 | try { 79 | obj.write(name, rvalue); 80 | return rvalue; 81 | } catch (AccessException e) { 82 | throw new StoneException("bad member access " + location() 83 | + ": " + name); 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/chap9/ClassInfo.java: -------------------------------------------------------------------------------- 1 | package chap9; 2 | import stone.StoneException; 3 | import stone.ast.ClassBody; 4 | import stone.ast.ClassStmnt; 5 | import chap6.Environment; 6 | 7 | public class ClassInfo { 8 | protected ClassStmnt definition; 9 | protected Environment environment; 10 | protected ClassInfo superClass; 11 | public ClassInfo(ClassStmnt cs, Environment env) { 12 | definition = cs; 13 | environment = env; 14 | Object obj = env.get(cs.superClass()); 15 | if (obj == null) 16 | superClass = null; 17 | else if (obj instanceof ClassInfo) 18 | superClass = (ClassInfo)obj; 19 | else 20 | throw new StoneException("unknown super class: " + cs.superClass(), 21 | cs); 22 | } 23 | public String name() { return definition.name(); } 24 | public ClassInfo superClass() { return superClass; } 25 | public ClassBody body() { return definition.body(); } 26 | public Environment environment() { return environment; } 27 | @Override public String toString() { return ""; } 28 | } 29 | -------------------------------------------------------------------------------- /src/chap9/ClassInterpreter.java: -------------------------------------------------------------------------------- 1 | package chap9; 2 | import stone.ClassParser; 3 | import stone.ParseException; 4 | import chap6.BasicInterpreter; 5 | import chap7.NestedEnv; 6 | import chap8.Natives; 7 | 8 | public class ClassInterpreter extends BasicInterpreter { 9 | public static void main(String[] args) throws ParseException { 10 | run(new ClassParser(), new Natives().environment(new NestedEnv())); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/chap9/ClassRunner.java: -------------------------------------------------------------------------------- 1 | package chap9; 2 | import javassist.gluonj.util.Loader; 3 | import chap7.ClosureEvaluator; 4 | import chap8.NativeEvaluator; 5 | 6 | public class ClassRunner { 7 | public static void main(String[] args) throws Throwable { 8 | Loader.run(ClassInterpreter.class, args, ClassEvaluator.class, 9 | NativeEvaluator.class, ClosureEvaluator.class); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/chap9/StoneObject.java: -------------------------------------------------------------------------------- 1 | package chap9; 2 | import chap6.Environment; 3 | import chap7.FuncEvaluator.EnvEx; 4 | 5 | public class StoneObject { 6 | public static class AccessException extends Exception {} 7 | protected Environment env; 8 | public StoneObject(Environment e) { env = e; } 9 | @Override public String toString() { return ""; } 10 | public Object read(String member) throws AccessException { 11 | return getEnv(member).get(member); 12 | } 13 | public void write(String member, Object value) throws AccessException { 14 | ((EnvEx)getEnv(member)).putNew(member, value); 15 | } 16 | protected Environment getEnv(String member) throws AccessException { 17 | Environment e = ((EnvEx)env).where(member); 18 | if (e != null && e == env) 19 | return e; 20 | else 21 | throw new AccessException(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/chapA/Lexer.java: -------------------------------------------------------------------------------- 1 | package chapA; 2 | import java.io.IOException; 3 | import java.io.Reader; 4 | import stone.CodeDialog; 5 | 6 | public class Lexer { 7 | private Reader reader; 8 | private static final int EMPTY = -1; 9 | private int lastChar = EMPTY; 10 | public Lexer(Reader r) { reader = r; } 11 | private int getChar() throws IOException { 12 | if (lastChar == EMPTY) 13 | return reader.read(); 14 | else { 15 | int c = lastChar; 16 | lastChar = EMPTY; 17 | return c; 18 | } 19 | } 20 | private void ungetChar(int c) { lastChar = c; } 21 | public String read() throws IOException { 22 | StringBuilder sb = new StringBuilder(); 23 | int c; 24 | do { 25 | c = getChar(); 26 | } while (isSpace(c)); 27 | if (c < 0) 28 | return null; // end of text 29 | else if (isDigit(c)) { 30 | do { 31 | sb.append((char)c); 32 | c = getChar(); 33 | } while (isDigit(c)); 34 | } 35 | else if (isLetter(c)) { 36 | do { 37 | sb.append((char)c); 38 | c = getChar(); 39 | } while (isLetter(c) || isDigit(c)); 40 | } 41 | else if (c == '=') { 42 | c = getChar(); 43 | if (c == '=') 44 | return "=="; 45 | else { 46 | ungetChar(c); 47 | return "="; 48 | } 49 | } 50 | else 51 | throw new IOException(); 52 | 53 | if (c >= 0) 54 | ungetChar(c); 55 | 56 | return sb.toString(); 57 | } 58 | private static boolean isLetter(int c) { 59 | return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'; 60 | } 61 | private static boolean isDigit(int c) { return '0' <= c && c <= '9'; } 62 | private static boolean isSpace(int c) { return 0 <= c && c <= ' '; } 63 | public static void main(String[] args) throws Exception { 64 | Lexer l = new Lexer(new CodeDialog()); 65 | for (String s; (s = l.read()) != null; ) 66 | System.out.println("-> " + s); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/chapB/ExprParser.java: -------------------------------------------------------------------------------- 1 | package chapB; 2 | import java.util.Arrays; 3 | import stone.*; 4 | import stone.ast.*; 5 | 6 | public class ExprParser { 7 | private Lexer lexer; 8 | 9 | public ExprParser(Lexer p) { 10 | lexer = p; 11 | } 12 | public ASTree expression() throws ParseException { 13 | ASTree left = term(); 14 | while (isToken("+") || isToken("-")) { 15 | ASTLeaf op = new ASTLeaf(lexer.read()); 16 | ASTree right = term(); 17 | left = new BinaryExpr(Arrays.asList(left, op, right)); 18 | } 19 | return left; 20 | } 21 | public ASTree term() throws ParseException { 22 | ASTree left = factor(); 23 | while (isToken("*") || isToken("/")) { 24 | ASTLeaf op = new ASTLeaf(lexer.read()); 25 | ASTree right = factor(); 26 | left = new BinaryExpr(Arrays.asList(left, op, right)); 27 | } 28 | return left; 29 | } 30 | public ASTree factor() throws ParseException { 31 | if (isToken("(")) { 32 | token("("); 33 | ASTree e = expression(); 34 | token(")"); 35 | return e; 36 | } 37 | else { 38 | Token t = lexer.read(); 39 | if (t.isNumber()) { 40 | NumberLiteral n = new NumberLiteral(t); 41 | return n; 42 | } 43 | else 44 | throw new ParseException(t); 45 | } 46 | } 47 | void token(String name) throws ParseException { 48 | Token t = lexer.read(); 49 | if (!(t.isIdentifier() && name.equals(t.getText()))) 50 | throw new ParseException(t); 51 | } 52 | boolean isToken(String name) throws ParseException { 53 | Token t = lexer.peek(0); 54 | return t.isIdentifier() && name.equals(t.getText()); 55 | } 56 | 57 | public static void main(String[] args) throws ParseException { 58 | Lexer lexer = new Lexer(new CodeDialog()); 59 | ExprParser p = new ExprParser(lexer); 60 | ASTree t = p.expression(); 61 | System.out.println("=> " + t); 62 | } 63 | } -------------------------------------------------------------------------------- /src/chapB/OpPrecedenceParser.java: -------------------------------------------------------------------------------- 1 | package chapB; 2 | import java.util.Arrays; 3 | import java.util.HashMap; 4 | import stone.*; 5 | import stone.ast.*; 6 | 7 | public class OpPrecedenceParser { 8 | private Lexer lexer; 9 | protected HashMap operators; 10 | 11 | public static class Precedence { 12 | int value; 13 | boolean leftAssoc; // left associative 14 | public Precedence(int v, boolean a) { 15 | value = v; leftAssoc = a; 16 | } 17 | } 18 | public OpPrecedenceParser(Lexer p) { 19 | lexer = p; 20 | operators = new HashMap(); 21 | operators.put("<", new Precedence(1, true)); 22 | operators.put(">", new Precedence(1, true)); 23 | operators.put("+", new Precedence(2, true)); 24 | operators.put("-", new Precedence(2, true)); 25 | operators.put("*", new Precedence(3, true)); 26 | operators.put("/", new Precedence(3, true)); 27 | operators.put("^", new Precedence(4, false)); 28 | } 29 | public ASTree expression() throws ParseException { 30 | ASTree right = factor(); 31 | Precedence next; 32 | while ((next = nextOperator()) != null) 33 | right = doShift(right, next.value); 34 | 35 | return right; 36 | } 37 | private ASTree doShift(ASTree left, int prec) throws ParseException { 38 | ASTLeaf op = new ASTLeaf(lexer.read()); 39 | ASTree right = factor(); 40 | Precedence next; 41 | while ((next = nextOperator()) != null && rightIsExpr(prec, next)) 42 | right = doShift(right, next.value); 43 | 44 | return new BinaryExpr(Arrays.asList(left, op, right)); 45 | } 46 | private Precedence nextOperator() throws ParseException { 47 | Token t = lexer.peek(0); 48 | if (t.isIdentifier()) 49 | return operators.get(t.getText()); 50 | else 51 | return null; 52 | } 53 | private static boolean rightIsExpr(int prec, Precedence nextPrec) { 54 | if (nextPrec.leftAssoc) 55 | return prec < nextPrec.value; 56 | else 57 | return prec <= nextPrec.value; 58 | } 59 | public ASTree factor() throws ParseException { 60 | if (isToken("(")) { 61 | token("("); 62 | ASTree e = expression(); 63 | token(")"); 64 | return e; 65 | } 66 | else { 67 | Token t = lexer.read(); 68 | if (t.isNumber()) { 69 | NumberLiteral n = new NumberLiteral(t); 70 | return n; 71 | } 72 | else 73 | throw new ParseException(t); 74 | } 75 | } 76 | void token(String name) throws ParseException { 77 | Token t = lexer.read(); 78 | if (!(t.isIdentifier() && name.equals(t.getText()))) 79 | throw new ParseException(t); 80 | } 81 | boolean isToken(String name) throws ParseException { 82 | Token t = lexer.peek(0); 83 | return t.isIdentifier() && name.equals(t.getText()); 84 | } 85 | public static void main(String[] args) throws ParseException { 86 | Lexer lexer = new Lexer(new CodeDialog()); 87 | OpPrecedenceParser p = new OpPrecedenceParser(lexer); 88 | ASTree t = p.expression(); 89 | System.out.println("=> " + t); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/stone/ArrayParser.java: -------------------------------------------------------------------------------- 1 | package stone; 2 | import static stone.Parser.rule; 3 | import javassist.gluonj.Reviser; 4 | import stone.ast.*; 5 | 6 | @Reviser public class ArrayParser extends FuncParser { 7 | Parser elements = rule(ArrayLiteral.class) 8 | .ast(expr).repeat(rule().sep(",").ast(expr)); 9 | public ArrayParser() { 10 | reserved.add("]"); 11 | primary.insertChoice(rule().sep("[").maybe(elements).sep("]")); 12 | postfix.insertChoice(rule(ArrayRef.class).sep("[").ast(expr).sep("]")); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/stone/BasicParser.java: -------------------------------------------------------------------------------- 1 | package stone; 2 | import static stone.Parser.rule; 3 | import java.util.HashSet; 4 | import stone.Parser.Operators; 5 | import stone.ast.*; 6 | 7 | public class BasicParser { 8 | HashSet reserved = new HashSet(); 9 | Operators operators = new Operators(); 10 | Parser expr0 = rule(); 11 | Parser primary = rule(PrimaryExpr.class) 12 | .or(rule().sep("(").ast(expr0).sep(")"), 13 | rule().number(NumberLiteral.class), 14 | rule().identifier(Name.class, reserved), 15 | rule().string(StringLiteral.class)); 16 | Parser factor = rule().or(rule(NegativeExpr.class).sep("-").ast(primary), 17 | primary); 18 | Parser expr = expr0.expression(BinaryExpr.class, factor, operators); 19 | 20 | Parser statement0 = rule(); 21 | Parser block = rule(BlockStmnt.class) 22 | .sep("{").option(statement0) 23 | .repeat(rule().sep(";", Token.EOL).option(statement0)) 24 | .sep("}"); 25 | Parser simple = rule(PrimaryExpr.class).ast(expr); 26 | Parser statement = statement0.or( 27 | rule(IfStmnt.class).sep("if").ast(expr).ast(block) 28 | .option(rule().sep("else").ast(block)), 29 | rule(WhileStmnt.class).sep("while").ast(expr).ast(block), 30 | simple); 31 | 32 | Parser program = rule().or(statement, rule(NullStmnt.class)) 33 | .sep(";", Token.EOL); 34 | 35 | public BasicParser() { 36 | reserved.add(";"); 37 | reserved.add("}"); 38 | reserved.add(Token.EOL); 39 | 40 | operators.add("=", 1, Operators.RIGHT); 41 | operators.add("==", 2, Operators.LEFT); 42 | operators.add(">", 2, Operators.LEFT); 43 | operators.add("<", 2, Operators.LEFT); 44 | operators.add("+", 3, Operators.LEFT); 45 | operators.add("-", 3, Operators.LEFT); 46 | operators.add("*", 4, Operators.LEFT); 47 | operators.add("/", 4, Operators.LEFT); 48 | operators.add("%", 4, Operators.LEFT); 49 | } 50 | public ASTree parse(Lexer lexer) throws ParseException { 51 | return program.parse(lexer); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/stone/ClassParser.java: -------------------------------------------------------------------------------- 1 | package stone; 2 | import static stone.Parser.rule; 3 | import stone.ast.ClassBody; 4 | import stone.ast.ClassStmnt; 5 | import stone.ast.Dot; 6 | 7 | public class ClassParser extends ClosureParser { 8 | Parser member = rule().or(def, simple); 9 | Parser class_body = rule(ClassBody.class).sep("{").option(member) 10 | .repeat(rule().sep(";", Token.EOL).option(member)) 11 | .sep("}"); 12 | Parser defclass = rule(ClassStmnt.class).sep("class").identifier(reserved) 13 | .option(rule().sep("extends").identifier(reserved)) 14 | .ast(class_body); 15 | public ClassParser() { 16 | postfix.insertChoice(rule(Dot.class).sep(".").identifier(reserved)); 17 | program.insertChoice(defclass); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/stone/ClosureParser.java: -------------------------------------------------------------------------------- 1 | package stone; 2 | import static stone.Parser.rule; 3 | import stone.ast.Fun; 4 | 5 | public class ClosureParser extends FuncParser { 6 | public ClosureParser() { 7 | primary.insertChoice(rule(Fun.class) 8 | .sep("fun").ast(paramList).ast(block)); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/stone/CodeDialog.java: -------------------------------------------------------------------------------- 1 | package stone; 2 | import java.io.FileReader; 3 | import java.io.BufferedReader; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.io.Reader; 7 | import javax.swing.JFileChooser; 8 | import javax.swing.JOptionPane; 9 | import javax.swing.JScrollPane; 10 | import javax.swing.JTextArea; 11 | 12 | public class CodeDialog extends Reader { 13 | private String buffer = null; 14 | private int pos = 0; 15 | 16 | public int read(char[] cbuf, int off, int len) throws IOException { 17 | if (buffer == null) { 18 | String in = showDialog(); 19 | if (in == null) 20 | return -1; 21 | else { 22 | print(in); 23 | buffer = in + "\n"; 24 | pos = 0; 25 | } 26 | } 27 | 28 | int size = 0; 29 | int length = buffer.length(); 30 | while (pos < length && size < len) 31 | cbuf[off + size++] = buffer.charAt(pos++); 32 | if (pos == length) 33 | buffer = null; 34 | return size; 35 | } 36 | protected void print(String s) { System.out.println(s); } 37 | public void close() throws IOException {} 38 | protected String showDialog() { 39 | JTextArea area = new JTextArea(20, 40); 40 | JScrollPane pane = new JScrollPane(area); 41 | int result = JOptionPane.showOptionDialog(null, pane, "Input", 42 | JOptionPane.OK_CANCEL_OPTION, 43 | JOptionPane.PLAIN_MESSAGE, 44 | null, null, null); 45 | if (result == JOptionPane.OK_OPTION) 46 | return area.getText(); 47 | else 48 | return null; 49 | } 50 | public static Reader file() throws FileNotFoundException { 51 | JFileChooser chooser = new JFileChooser(); 52 | if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) 53 | return new BufferedReader(new FileReader(chooser.getSelectedFile())); 54 | else 55 | throw new FileNotFoundException("no file specified"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/stone/FuncParser.java: -------------------------------------------------------------------------------- 1 | package stone; 2 | import static stone.Parser.rule; 3 | import stone.ast.ParameterList; 4 | import stone.ast.Arguments; 5 | import stone.ast.DefStmnt; 6 | 7 | public class FuncParser extends BasicParser { 8 | Parser param = rule().identifier(reserved); 9 | Parser params = rule(ParameterList.class) 10 | .ast(param).repeat(rule().sep(",").ast(param)); 11 | Parser paramList = rule().sep("(").maybe(params).sep(")"); 12 | Parser def = rule(DefStmnt.class) 13 | .sep("def").identifier(reserved).ast(paramList).ast(block); 14 | Parser args = rule(Arguments.class) 15 | .ast(expr).repeat(rule().sep(",").ast(expr)); 16 | Parser postfix = rule().sep("(").maybe(args).sep(")"); 17 | 18 | public FuncParser() { 19 | reserved.add(")"); 20 | primary.repeat(postfix); 21 | simple.option(args); 22 | program.insertChoice(def); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/stone/Lexer.java: -------------------------------------------------------------------------------- 1 | package stone; 2 | import java.io.IOException; 3 | import java.io.LineNumberReader; 4 | import java.io.Reader; 5 | import java.util.ArrayList; 6 | import java.util.regex.Matcher; 7 | import java.util.regex.Pattern; 8 | 9 | public class Lexer { 10 | public static String regexPat 11 | = "\\s*((//.*)|([0-9]+)|(\"(\\\\\"|\\\\\\\\|\\\\n|[^\"])*\")" 12 | + "|[A-Z_a-z][A-Z_a-z0-9]*|==|<=|>=|&&|\\|\\||\\p{Punct})?"; 13 | private Pattern pattern = Pattern.compile(regexPat); 14 | private ArrayList queue = new ArrayList(); 15 | private boolean hasMore; 16 | private LineNumberReader reader; 17 | 18 | public Lexer(Reader r) { 19 | hasMore = true; 20 | reader = new LineNumberReader(r); 21 | } 22 | public Token read() throws ParseException { 23 | if (fillQueue(0)) 24 | return queue.remove(0); 25 | else 26 | return Token.EOF; 27 | } 28 | public Token peek(int i) throws ParseException { 29 | if (fillQueue(i)) 30 | return queue.get(i); 31 | else 32 | return Token.EOF; 33 | } 34 | private boolean fillQueue(int i) throws ParseException { 35 | while (i >= queue.size()) 36 | if (hasMore) 37 | readLine(); 38 | else 39 | return false; 40 | return true; 41 | } 42 | protected void readLine() throws ParseException { 43 | String line; 44 | try { 45 | line = reader.readLine(); 46 | } catch (IOException e) { 47 | throw new ParseException(e); 48 | } 49 | if (line == null) { 50 | hasMore = false; 51 | return; 52 | } 53 | int lineNo = reader.getLineNumber(); 54 | Matcher matcher = pattern.matcher(line); 55 | matcher.useTransparentBounds(true).useAnchoringBounds(false); 56 | int pos = 0; 57 | int endPos = line.length(); 58 | while (pos < endPos) { 59 | matcher.region(pos, endPos); 60 | if (matcher.lookingAt()) { 61 | addToken(lineNo, matcher); 62 | pos = matcher.end(); 63 | } 64 | else 65 | throw new ParseException("bad token at line " + lineNo); 66 | } 67 | queue.add(new IdToken(lineNo, Token.EOL)); 68 | } 69 | protected void addToken(int lineNo, Matcher matcher) { 70 | String m = matcher.group(1); 71 | if (m != null) // if not a space 72 | if (matcher.group(2) == null) { // if not a comment 73 | Token token; 74 | if (matcher.group(3) != null) 75 | token = new NumToken(lineNo, Integer.parseInt(m)); 76 | else if (matcher.group(4) != null) 77 | token = new StrToken(lineNo, toStringLiteral(m)); 78 | else 79 | token = new IdToken(lineNo, m); 80 | queue.add(token); 81 | } 82 | } 83 | protected String toStringLiteral(String s) { 84 | StringBuilder sb = new StringBuilder(); 85 | int len = s.length() - 1; 86 | for (int i = 1; i < len; i++) { 87 | char c = s.charAt(i); 88 | if (c == '\\' && i + 1 < len) { 89 | char c2 = s.charAt(i + 1); 90 | if (c2 == '"' || c2 == '\\') 91 | c = s.charAt(++i); 92 | else if (c2 == 'n') { 93 | ++i; 94 | c = '\n'; 95 | } 96 | } 97 | sb.append(c); 98 | } 99 | return sb.toString(); 100 | } 101 | 102 | protected static class NumToken extends Token { 103 | private int value; 104 | 105 | protected NumToken(int line, int v) { 106 | super(line); 107 | value = v; 108 | } 109 | public boolean isNumber() { return true; } 110 | public String getText() { return Integer.toString(value); } 111 | public int getNumber() { return value; } 112 | } 113 | 114 | protected static class IdToken extends Token { 115 | private String text; 116 | protected IdToken(int line, String id) { 117 | super(line); 118 | text = id; 119 | } 120 | public boolean isIdentifier() { return true; } 121 | public String getText() { return text; } 122 | } 123 | 124 | protected static class StrToken extends Token { 125 | private String literal; 126 | StrToken(int line, String str) { 127 | super(line); 128 | literal = str; 129 | } 130 | public boolean isString() { return true; } 131 | public String getText() { return literal; } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/stone/ParseException.java: -------------------------------------------------------------------------------- 1 | package stone; 2 | import java.io.IOException; 3 | 4 | public class ParseException extends Exception { 5 | public ParseException(Token t) { 6 | this("", t); 7 | } 8 | public ParseException(String msg, Token t) { 9 | super("syntax error around " + location(t) + ". " + msg); 10 | } 11 | private static String location(Token t) { 12 | if (t == Token.EOF) 13 | return "the last line"; 14 | else 15 | return "\"" + t.getText() + "\" at line " + t.getLineNumber(); 16 | } 17 | public ParseException(IOException e) { 18 | super(e); 19 | } 20 | public ParseException(String msg) { 21 | super(msg); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/stone/Parser.java: -------------------------------------------------------------------------------- 1 | package stone; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | import java.util.List; 6 | import java.util.ArrayList; 7 | import java.lang.reflect.Method; 8 | import java.lang.reflect.Constructor; 9 | import stone.ast.ASTree; 10 | import stone.ast.ASTLeaf; 11 | import stone.ast.ASTList; 12 | 13 | public class Parser { 14 | protected static abstract class Element { 15 | protected abstract void parse(Lexer lexer, List res) 16 | throws ParseException; 17 | protected abstract boolean match(Lexer lexer) throws ParseException; 18 | } 19 | 20 | protected static class Tree extends Element { 21 | protected Parser parser; 22 | protected Tree(Parser p) { parser = p; } 23 | protected void parse(Lexer lexer, List res) 24 | throws ParseException 25 | { 26 | res.add(parser.parse(lexer)); 27 | } 28 | protected boolean match(Lexer lexer) throws ParseException { 29 | return parser.match(lexer); 30 | } 31 | } 32 | 33 | protected static class OrTree extends Element { 34 | protected Parser[] parsers; 35 | protected OrTree(Parser[] p) { parsers = p; } 36 | protected void parse(Lexer lexer, List res) 37 | throws ParseException 38 | { 39 | Parser p = choose(lexer); 40 | if (p == null) 41 | throw new ParseException(lexer.peek(0)); 42 | else 43 | res.add(p.parse(lexer)); 44 | } 45 | protected boolean match(Lexer lexer) throws ParseException { 46 | return choose(lexer) != null; 47 | } 48 | protected Parser choose(Lexer lexer) throws ParseException { 49 | for (Parser p: parsers) 50 | if (p.match(lexer)) 51 | return p; 52 | 53 | return null; 54 | } 55 | protected void insert(Parser p) { 56 | Parser[] newParsers = new Parser[parsers.length + 1]; 57 | newParsers[0] = p; 58 | System.arraycopy(parsers, 0, newParsers, 1, parsers.length); 59 | parsers = newParsers; 60 | } 61 | } 62 | 63 | protected static class Repeat extends Element { 64 | protected Parser parser; 65 | protected boolean onlyOnce; 66 | protected Repeat(Parser p, boolean once) { parser = p; onlyOnce = once; } 67 | protected void parse(Lexer lexer, List res) 68 | throws ParseException 69 | { 70 | while (parser.match(lexer)) { 71 | ASTree t = parser.parse(lexer); 72 | if (t.getClass() != ASTList.class || t.numChildren() > 0) 73 | res.add(t); 74 | if (onlyOnce) 75 | break; 76 | } 77 | } 78 | protected boolean match(Lexer lexer) throws ParseException { 79 | return parser.match(lexer); 80 | } 81 | } 82 | 83 | protected static abstract class AToken extends Element { 84 | protected Factory factory; 85 | protected AToken(Class type) { 86 | if (type == null) 87 | type = ASTLeaf.class; 88 | factory = Factory.get(type, Token.class); 89 | } 90 | protected void parse(Lexer lexer, List res) 91 | throws ParseException 92 | { 93 | Token t = lexer.read(); 94 | if (test(t)) { 95 | ASTree leaf = factory.make(t); 96 | res.add(leaf); 97 | } 98 | else 99 | throw new ParseException(t); 100 | } 101 | protected boolean match(Lexer lexer) throws ParseException { 102 | return test(lexer.peek(0)); 103 | } 104 | protected abstract boolean test(Token t); 105 | } 106 | 107 | protected static class IdToken extends AToken { 108 | HashSet reserved; 109 | protected IdToken(Class type, HashSet r) { 110 | super(type); 111 | reserved = r != null ? r : new HashSet(); 112 | } 113 | protected boolean test(Token t) { 114 | return t.isIdentifier() && !reserved.contains(t.getText()); 115 | } 116 | } 117 | 118 | protected static class NumToken extends AToken { 119 | protected NumToken(Class type) { super(type); } 120 | protected boolean test(Token t) { return t.isNumber(); } 121 | } 122 | 123 | protected static class StrToken extends AToken { 124 | protected StrToken(Class type) { super(type); } 125 | protected boolean test(Token t) { return t.isString(); } 126 | } 127 | 128 | protected static class Leaf extends Element { 129 | protected String[] tokens; 130 | protected Leaf(String[] pat) { tokens = pat; } 131 | protected void parse(Lexer lexer, List res) 132 | throws ParseException 133 | { 134 | Token t = lexer.read(); 135 | if (t.isIdentifier()) 136 | for (String token: tokens) 137 | if (token.equals(t.getText())) { 138 | find(res, t); 139 | return; 140 | } 141 | 142 | if (tokens.length > 0) 143 | throw new ParseException(tokens[0] + " expected.", t); 144 | else 145 | throw new ParseException(t); 146 | } 147 | protected void find(List res, Token t) { 148 | res.add(new ASTLeaf(t)); 149 | } 150 | protected boolean match(Lexer lexer) throws ParseException { 151 | Token t = lexer.peek(0); 152 | if (t.isIdentifier()) 153 | for (String token: tokens) 154 | if (token.equals(t.getText())) 155 | return true; 156 | 157 | return false; 158 | } 159 | } 160 | 161 | protected static class Skip extends Leaf { 162 | protected Skip(String[] t) { super(t); } 163 | protected void find(List res, Token t) {} 164 | } 165 | 166 | public static class Precedence { 167 | int value; 168 | boolean leftAssoc; // left associative 169 | public Precedence(int v, boolean a) { 170 | value = v; leftAssoc = a; 171 | } 172 | } 173 | 174 | public static class Operators extends HashMap { 175 | public static boolean LEFT = true; 176 | public static boolean RIGHT = false; 177 | public void add(String name, int prec, boolean leftAssoc) { 178 | put(name, new Precedence(prec, leftAssoc)); 179 | } 180 | } 181 | 182 | protected static class Expr extends Element { 183 | protected Factory factory; 184 | protected Operators ops; 185 | protected Parser factor; 186 | protected Expr(Class clazz, Parser exp, 187 | Operators map) 188 | { 189 | factory = Factory.getForASTList(clazz); 190 | ops = map; 191 | factor = exp; 192 | } 193 | public void parse(Lexer lexer, List res) throws ParseException { 194 | ASTree right = factor.parse(lexer); 195 | Precedence prec; 196 | while ((prec = nextOperator(lexer)) != null) 197 | right = doShift(lexer, right, prec.value); 198 | 199 | res.add(right); 200 | } 201 | private ASTree doShift(Lexer lexer, ASTree left, int prec) 202 | throws ParseException 203 | { 204 | ArrayList list = new ArrayList(); 205 | list.add(left); 206 | list.add(new ASTLeaf(lexer.read())); 207 | ASTree right = factor.parse(lexer); 208 | Precedence next; 209 | while ((next = nextOperator(lexer)) != null 210 | && rightIsExpr(prec, next)) 211 | right = doShift(lexer, right, next.value); 212 | 213 | list.add(right); 214 | return factory.make(list); 215 | } 216 | private Precedence nextOperator(Lexer lexer) throws ParseException { 217 | Token t = lexer.peek(0); 218 | if (t.isIdentifier()) 219 | return ops.get(t.getText()); 220 | else 221 | return null; 222 | } 223 | private static boolean rightIsExpr(int prec, Precedence nextPrec) { 224 | if (nextPrec.leftAssoc) 225 | return prec < nextPrec.value; 226 | else 227 | return prec <= nextPrec.value; 228 | } 229 | protected boolean match(Lexer lexer) throws ParseException { 230 | return factor.match(lexer); 231 | } 232 | } 233 | 234 | public static final String factoryName = "create"; 235 | protected static abstract class Factory { 236 | protected abstract ASTree make0(Object arg) throws Exception; 237 | protected ASTree make(Object arg) { 238 | try { 239 | return make0(arg); 240 | } catch (IllegalArgumentException e1) { 241 | throw e1; 242 | } catch (Exception e2) { 243 | throw new RuntimeException(e2); // this compiler is broken. 244 | } 245 | } 246 | protected static Factory getForASTList(Class clazz) { 247 | Factory f = get(clazz, List.class); 248 | if (f == null) 249 | f = new Factory() { 250 | protected ASTree make0(Object arg) throws Exception { 251 | @SuppressWarnings("unchecked") 252 | List results = (List)arg; 253 | if (results.size() == 1) 254 | return results.get(0); 255 | else 256 | return new ASTList(results); 257 | } 258 | }; 259 | return f; 260 | } 261 | protected static Factory get(Class clazz, 262 | Class argType) 263 | { 264 | if (clazz == null) 265 | return null; 266 | try { 267 | final Method m = clazz.getMethod(factoryName, 268 | new Class[] { argType }); 269 | return new Factory() { 270 | protected ASTree make0(Object arg) throws Exception { 271 | return (ASTree)m.invoke(null, arg); 272 | } 273 | }; 274 | } catch (NoSuchMethodException e) {} 275 | try { 276 | final Constructor c 277 | = clazz.getConstructor(argType); 278 | return new Factory() { 279 | protected ASTree make0(Object arg) throws Exception { 280 | return c.newInstance(arg); 281 | } 282 | }; 283 | } catch (NoSuchMethodException e) { 284 | throw new RuntimeException(e); 285 | } 286 | } 287 | } 288 | 289 | protected List elements; 290 | protected Factory factory; 291 | 292 | public Parser(Class clazz) { 293 | reset(clazz); 294 | } 295 | protected Parser(Parser p) { 296 | elements = p.elements; 297 | factory = p.factory; 298 | } 299 | public ASTree parse(Lexer lexer) throws ParseException { 300 | ArrayList results = new ArrayList(); 301 | for (Element e: elements) 302 | e.parse(lexer, results); 303 | 304 | return factory.make(results); 305 | } 306 | protected boolean match(Lexer lexer) throws ParseException { 307 | if (elements.size() == 0) 308 | return true; 309 | else { 310 | Element e = elements.get(0); 311 | return e.match(lexer); 312 | } 313 | } 314 | public static Parser rule() { return rule(null); } 315 | public static Parser rule(Class clazz) { 316 | return new Parser(clazz); 317 | } 318 | public Parser reset() { 319 | elements = new ArrayList(); 320 | return this; 321 | } 322 | public Parser reset(Class clazz) { 323 | elements = new ArrayList(); 324 | factory = Factory.getForASTList(clazz); 325 | return this; 326 | } 327 | public Parser number() { 328 | return number(null); 329 | } 330 | public Parser number(Class clazz) { 331 | elements.add(new NumToken(clazz)); 332 | return this; 333 | } 334 | public Parser identifier(HashSet reserved) { 335 | return identifier(null, reserved); 336 | } 337 | public Parser identifier(Class clazz, 338 | HashSet reserved) 339 | { 340 | elements.add(new IdToken(clazz, reserved)); 341 | return this; 342 | } 343 | public Parser string() { 344 | return string(null); 345 | } 346 | public Parser string(Class clazz) { 347 | elements.add(new StrToken(clazz)); 348 | return this; 349 | } 350 | public Parser token(String... pat) { 351 | elements.add(new Leaf(pat)); 352 | return this; 353 | } 354 | public Parser sep(String... pat) { 355 | elements.add(new Skip(pat)); 356 | return this; 357 | } 358 | public Parser ast(Parser p) { 359 | elements.add(new Tree(p)); 360 | return this; 361 | } 362 | public Parser or(Parser... p) { 363 | elements.add(new OrTree(p)); 364 | return this; 365 | } 366 | public Parser maybe(Parser p) { 367 | Parser p2 = new Parser(p); 368 | p2.reset(); 369 | elements.add(new OrTree(new Parser[] { p, p2 })); 370 | return this; 371 | } 372 | public Parser option(Parser p) { 373 | elements.add(new Repeat(p, true)); 374 | return this; 375 | } 376 | public Parser repeat(Parser p) { 377 | elements.add(new Repeat(p, false)); 378 | return this; 379 | } 380 | public Parser expression(Parser subexp, Operators operators) { 381 | elements.add(new Expr(null, subexp, operators)); 382 | return this; 383 | } 384 | public Parser expression(Class clazz, Parser subexp, 385 | Operators operators) { 386 | elements.add(new Expr(clazz, subexp, operators)); 387 | return this; 388 | } 389 | public Parser insertChoice(Parser p) { 390 | Element e = elements.get(0); 391 | if (e instanceof OrTree) 392 | ((OrTree)e).insert(p); 393 | else { 394 | Parser otherwise = new Parser(this); 395 | reset(null); 396 | or(p, otherwise); 397 | } 398 | return this; 399 | } 400 | } 401 | -------------------------------------------------------------------------------- /src/stone/StoneException.java: -------------------------------------------------------------------------------- 1 | package stone; 2 | import stone.ast.ASTree; 3 | 4 | public class StoneException extends RuntimeException { 5 | public StoneException(String m) { super(m); } 6 | public StoneException(String m, ASTree t) { 7 | super(m + " " + t.location()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/stone/Token.java: -------------------------------------------------------------------------------- 1 | package stone; 2 | 3 | public abstract class Token { 4 | public static final Token EOF = new Token(-1){}; // end of file 5 | public static final String EOL = "\\n"; // end of line 6 | private int lineNumber; 7 | 8 | protected Token(int line) { 9 | lineNumber = line; 10 | } 11 | public int getLineNumber() { return lineNumber; } 12 | public boolean isIdentifier() { return false; } 13 | public boolean isNumber() { return false; } 14 | public boolean isString() { return false; } 15 | public int getNumber() { throw new StoneException("not number token"); } 16 | public String getText() { return ""; } 17 | } 18 | -------------------------------------------------------------------------------- /src/stone/TypedParser.java: -------------------------------------------------------------------------------- 1 | package stone; 2 | import static stone.Parser.rule; 3 | import stone.ast.*; 4 | 5 | public class TypedParser extends FuncParser { 6 | Parser typeTag = rule(TypeTag.class).sep(":").identifier(reserved); 7 | Parser variable = rule(VarStmnt.class) 8 | .sep("var").identifier(reserved).maybe(typeTag) 9 | .sep("=").ast(expr); 10 | public TypedParser() { 11 | reserved.add(":"); 12 | param.maybe(typeTag); 13 | def.reset().sep("def").identifier(reserved).ast(paramList) 14 | .maybe(typeTag).ast(block); 15 | statement.insertChoice(variable); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/stone/ast/ASTLeaf.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.Iterator; 3 | import java.util.ArrayList; 4 | import stone.Token; 5 | 6 | public class ASTLeaf extends ASTree { 7 | private static ArrayList empty = new ArrayList(); 8 | protected Token token; 9 | public ASTLeaf(Token t) { token = t; } 10 | public ASTree child(int i) { throw new IndexOutOfBoundsException(); } 11 | public int numChildren() { return 0; } 12 | public Iterator children() { return empty.iterator(); } 13 | public String toString() { return token.getText(); } 14 | public String location() { return "at line " + token.getLineNumber(); } 15 | public Token token() { return token; } 16 | } 17 | -------------------------------------------------------------------------------- /src/stone/ast/ASTList.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | import java.util.Iterator; 4 | 5 | public class ASTList extends ASTree { 6 | protected List children; 7 | public ASTList(List list) { children = list; } 8 | public ASTree child(int i) { return children.get(i); } 9 | public int numChildren() { return children.size(); } 10 | public Iterator children() { return children.iterator(); } 11 | public String toString() { 12 | StringBuilder builder = new StringBuilder(); 13 | builder.append('('); 14 | String sep = ""; 15 | for (ASTree t: children) { 16 | builder.append(sep); 17 | sep = " "; 18 | builder.append(t.toString()); 19 | } 20 | return builder.append(')').toString(); 21 | } 22 | public String location() { 23 | for (ASTree t: children) { 24 | String s = t.location(); 25 | if (s != null) 26 | return s; 27 | } 28 | return null; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/stone/ast/ASTree.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.Iterator; 3 | 4 | public abstract class ASTree implements Iterable { 5 | public abstract ASTree child(int i); 6 | public abstract int numChildren(); 7 | public abstract Iterator children(); 8 | public abstract String location(); 9 | public Iterator iterator() { return children(); } 10 | } 11 | -------------------------------------------------------------------------------- /src/stone/ast/Arguments.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class Arguments extends Postfix { 5 | public Arguments(List c) { super(c); } 6 | public int size() { return numChildren(); } 7 | } 8 | -------------------------------------------------------------------------------- /src/stone/ast/ArrayLiteral.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class ArrayLiteral extends ASTList { 5 | public ArrayLiteral(List list) { super(list); } 6 | public int size() { return numChildren(); } 7 | } 8 | -------------------------------------------------------------------------------- /src/stone/ast/ArrayRef.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class ArrayRef extends Postfix { 5 | public ArrayRef(List c) { super(c); } 6 | public ASTree index() { return child(0); } 7 | public String toString() { return "[" + index() + "]"; } 8 | } 9 | -------------------------------------------------------------------------------- /src/stone/ast/BinaryExpr.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class BinaryExpr extends ASTList { 5 | public BinaryExpr(List c) { super(c); } 6 | public ASTree left() { return child(0); } 7 | public String operator() { 8 | return ((ASTLeaf)child(1)).token().getText(); 9 | } 10 | public ASTree right() { return child(2); } 11 | } 12 | -------------------------------------------------------------------------------- /src/stone/ast/BlockStmnt.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class BlockStmnt extends ASTList { 5 | public BlockStmnt(List c) { super(c); } 6 | } 7 | -------------------------------------------------------------------------------- /src/stone/ast/ClassBody.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class ClassBody extends ASTList { 5 | public ClassBody(List c) { super(c); } 6 | } -------------------------------------------------------------------------------- /src/stone/ast/ClassStmnt.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class ClassStmnt extends ASTList { 5 | public ClassStmnt(List c) { super(c); } 6 | public String name() { return ((ASTLeaf)child(0)).token().getText(); } 7 | public String superClass() { 8 | if (numChildren() < 3) 9 | return null; 10 | else 11 | return ((ASTLeaf)child(1)).token().getText(); 12 | } 13 | public ClassBody body() { return (ClassBody)child(numChildren() - 1); } 14 | public String toString() { 15 | String parent = superClass(); 16 | if (parent == null) 17 | parent = "*"; 18 | return "(class " + name() + " " + parent + " " + body() + ")"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/stone/ast/DefStmnt.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class DefStmnt extends ASTList { 5 | public DefStmnt(List c) { super(c); } 6 | public String name() { return ((ASTLeaf)child(0)).token().getText(); } 7 | public ParameterList parameters() { return (ParameterList)child(1); } 8 | public BlockStmnt body() { return (BlockStmnt)child(2); } 9 | public String toString() { 10 | return "(def " + name() + " " + parameters() + " " + body() + ")"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/stone/ast/Dot.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class Dot extends Postfix { 5 | public Dot(List c) { super(c); } 6 | public String name() { return ((ASTLeaf)child(0)).token().getText(); } 7 | public String toString() { return "." + name(); } 8 | } 9 | -------------------------------------------------------------------------------- /src/stone/ast/Fun.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class Fun extends ASTList { 5 | public Fun(List c) { super(c); } 6 | public ParameterList parameters() { return (ParameterList)child(0); } 7 | public BlockStmnt body() { return (BlockStmnt)child(1); } 8 | public String toString() { 9 | return "(fun " + parameters() + " " + body() + ")"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/stone/ast/IfStmnt.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class IfStmnt extends ASTList { 5 | public IfStmnt(List c) { super(c); } 6 | public ASTree condition() { return child(0); } 7 | public ASTree thenBlock() { return child(1); } 8 | public ASTree elseBlock() { 9 | return numChildren() > 2 ? child(2) : null; 10 | } 11 | public String toString() { 12 | return "(if " + condition() + " " + thenBlock() 13 | + " else " + elseBlock() + ")"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/stone/ast/Name.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import stone.Token; 3 | 4 | public class Name extends ASTLeaf { 5 | public Name(Token t) { super(t); } 6 | public String name() { return token().getText(); } 7 | } 8 | -------------------------------------------------------------------------------- /src/stone/ast/NegativeExpr.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class NegativeExpr extends ASTList { 5 | public NegativeExpr(List c) { super(c); } 6 | public ASTree operand() { return child(0); } 7 | public String toString() { 8 | return "-" + operand(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/stone/ast/NullStmnt.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class NullStmnt extends ASTList { 5 | public NullStmnt(List c) { super(c); } 6 | } 7 | -------------------------------------------------------------------------------- /src/stone/ast/NumberLiteral.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import stone.Token; 3 | 4 | public class NumberLiteral extends ASTLeaf { 5 | public NumberLiteral(Token t) { super(t); } 6 | public int value() { return token().getNumber(); } 7 | } 8 | -------------------------------------------------------------------------------- /src/stone/ast/ParameterList.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class ParameterList extends ASTList { 5 | public ParameterList(List c) { super(c); } 6 | public String name(int i) { return ((ASTLeaf)child(i)).token().getText(); } 7 | public int size() { return numChildren(); } 8 | } 9 | -------------------------------------------------------------------------------- /src/stone/ast/Postfix.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | 3 | import java.util.List; 4 | 5 | public abstract class Postfix extends ASTList { 6 | public Postfix(List c) { super(c); } 7 | } 8 | -------------------------------------------------------------------------------- /src/stone/ast/PrimaryExpr.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class PrimaryExpr extends ASTList { 5 | public PrimaryExpr(List c) { super(c); } 6 | public static ASTree create(List c) { 7 | return c.size() == 1 ? c.get(0) : new PrimaryExpr(c); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/stone/ast/StringLiteral.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import stone.Token; 3 | 4 | public class StringLiteral extends ASTLeaf { 5 | public StringLiteral(Token t) { super(t); } 6 | public String value() { return token().getText(); } 7 | } 8 | -------------------------------------------------------------------------------- /src/stone/ast/TypeTag.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class TypeTag extends ASTList { 5 | public static final String UNDEF = ""; 6 | public TypeTag(List c) { super(c); } 7 | public String type() { 8 | if (numChildren() > 0) 9 | return ((ASTLeaf)child(0)).token().getText(); 10 | else 11 | return UNDEF; 12 | } 13 | public String toString() { return ":" + type(); } 14 | } 15 | -------------------------------------------------------------------------------- /src/stone/ast/VarStmnt.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class VarStmnt extends ASTList { 5 | public VarStmnt(List c) { super(c); } 6 | public String name() { return ((ASTLeaf)child(0)).token().getText(); } 7 | public TypeTag type() { return (TypeTag)child(1); } 8 | public ASTree initializer() { return child(2); } 9 | public String toString() { 10 | return "(var " + name() + " " + type() + " " + initializer() + ")"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/stone/ast/WhileStmnt.java: -------------------------------------------------------------------------------- 1 | package stone.ast; 2 | import java.util.List; 3 | 4 | public class WhileStmnt extends ASTList { 5 | public WhileStmnt(List c) { super(c); } 6 | public ASTree condition() { return child(0); } 7 | public ASTree body() { return child(1); } 8 | public String toString() { 9 | return "(while " + condition() + " " + body() + ")"; 10 | } 11 | } 12 | --------------------------------------------------------------------------------