├── .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 extends ASTLeaf> 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 extends ASTLeaf> 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 extends ASTLeaf> 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 extends ASTLeaf> 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 extends ASTree> 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 extends ASTree> 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 extends ASTree> 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 extends ASTree> 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 extends ASTree> 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 extends ASTree> clazz) {
316 | return new Parser(clazz);
317 | }
318 | public Parser reset() {
319 | elements = new ArrayList();
320 | return this;
321 | }
322 | public Parser reset(Class extends ASTree> 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 extends ASTLeaf> 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 extends ASTLeaf> 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 extends ASTLeaf> 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 extends ASTree> 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 |
--------------------------------------------------------------------------------