├── .gitignore
├── README.md
├── build.xml
└── java
└── com
└── simplemain
└── kit
└── json
├── Main.java
├── element
├── IllegalElement.java
├── JsonArray.java
├── JsonBoolean.java
├── JsonElement.java
├── JsonNull.java
├── JsonNumber.java
├── JsonObject.java
├── JsonString.java
└── Token.java
├── error
├── SyntaxError.java
├── SyntaxException.java
└── SyntaxWarning.java
├── format
├── JsonFormatter.java
├── MetaFormatter.java
└── TextJsonFormatter.java
└── parser
├── ArrayParser.java
├── BooleanParser.java
├── ElementParser.java
├── JsonParser.java
├── NullParser.java
├── NumberParser.java
├── ObjectParser.java
├── StringParser.java
├── Symbol.java
└── ValueParser.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /bin
2 | /.settings
3 | /.project
4 | /.classpath
5 | /logs
6 | /jar
7 | /.DS_Store
8 | /data
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JSON Parser & Formatter
2 |
3 | 前一段时间在用JSON的时候,发现格式化JSON很有意思,于是乎老王就用空闲时间写了一个JSON的解析和格式化器。
4 | 这个解析的状态机严格按照JSON规范来编写,详细见: [http://www.json.org/](http://www.json.org/)
5 |
6 |
7 | ## 代码组织
8 |
9 | ### Java代码: 在项目的/java目录下, 包名com.simplemain.kit.json
10 | * element: 存放的是Json的实体对象
11 | * error: 错误相关的类,分为错误和警告
12 | * format: 做格式化的类,都从JsonFormatter继承。可以自己继承实现想要的效果
13 | * parser: 解析类。对外接口为JsonParser类。
14 | * Main.java: 入口main函数类
15 |
16 | ### JavaScript代码: 待开发
17 |
18 | ### C代码: 待开发
19 |
20 | ## 编译 & 运行
21 | * 下载相关代码
22 | * 切换到项目目录
23 | * 编译: ant
24 | * 运行: java -jar jar/json-formatter-1.0.0.jar
25 | * 版本号有可能发生变化,请根据编译后的文件执行相应的命令
26 |
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | build done!
24 |
25 |
26 |
27 |
28 | clean
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/Main.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json;
2 |
3 | import java.io.PrintWriter;
4 |
5 | import com.simplemain.kit.json.element.JsonElement;
6 | import com.simplemain.kit.json.format.TextJsonFormatter;
7 | import com.simplemain.kit.json.parser.JsonParser;
8 |
9 | /**
10 | * @author zgwangbo@simplemain.com
11 | */
12 | public class Main
13 | {
14 | public static void main(String[] args)
15 | {
16 | final String json = "{'number':123, \"hello\":\"\\ux343\\u0041bCd\\uD83D\\uDE03\\r\\b\\f\\p\", \"111\":22,\"aa\": {'a':'b'}, 'array':['asdf', 123, null, true, false, 0.00003e-17, {'ddd':123,'hahah':[{}]},true]}aa";
17 |
18 | System.out.println("==== origin json string ====");
19 | System.out.println(json);
20 | System.out.println();
21 |
22 | final JsonParser jp = new JsonParser();
23 | final JsonElement je = jp.parse(json);
24 |
25 | System.out.println("==== formatted json string ====");
26 | try (PrintWriter pw = new PrintWriter(System.out))
27 | {
28 | new TextJsonFormatter(true, true, true).format(je, pw);
29 | }
30 | }
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/element/IllegalElement.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.element;
2 |
3 | import java.util.Iterator;
4 |
5 | import com.simplemain.kit.json.error.SyntaxException;
6 |
7 | /**
8 | * @author zgwangbo@simplemain.com
9 | */
10 | public class IllegalElement extends JsonElement
11 | {
12 | private String string;
13 |
14 | public IllegalElement(String s, SyntaxException e)
15 | {
16 | string = s;
17 | addException(e);
18 | }
19 |
20 | public String toString()
21 | {
22 | return string;
23 | }
24 |
25 | @Override
26 | public Iterator iterator()
27 | {
28 | return new SimpleIterator(new Token(toString(), Token.TYPE_STRING, level));
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/element/JsonArray.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.element;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Iterator;
5 | import java.util.List;
6 |
7 | /**
8 | * @author zgwangbo@simplemain.com
9 | */
10 | public class JsonArray extends JsonElement
11 | {
12 | public static final char BEGIN_SYMBOL = '[';
13 | public static final char END_SYMBOL = ']';
14 | public static final char NEXT_SEPARATOR = ',';
15 |
16 | private List elements = new ArrayList<>();
17 |
18 | private String beginSymbol = "";
19 | private String endSymbol = "";
20 |
21 | public void fillBeginSymbol()
22 | {
23 | beginSymbol = "" + BEGIN_SYMBOL;
24 | }
25 |
26 | public void fillEndSymbol()
27 | {
28 | endSymbol = "" + END_SYMBOL;
29 | }
30 |
31 | public void add(JsonElement e)
32 | {
33 | elements.add(e);
34 | }
35 |
36 | @Override
37 | public String toString()
38 | {
39 | StringBuffer sb = new StringBuffer();
40 | sb.append(beginSymbol);
41 |
42 | boolean first = true;
43 | for (JsonElement e : elements)
44 | {
45 | if (!first) sb.append(NEXT_SEPARATOR + " ");
46 | else first = false;
47 |
48 | sb.append(e.toString());
49 | }
50 | sb.append(endSymbol);
51 |
52 | return sb.toString();
53 | }
54 |
55 | @Override
56 | public Iterator iterator()
57 | {
58 | return new DefaultIterator();
59 | }
60 |
61 | private class DefaultIterator implements Iterator
62 | {
63 | protected List> iters = new ArrayList<>();
64 | protected int elementIdx = 0;
65 |
66 | DefaultIterator()
67 | {
68 | iters.add(new SimpleIterator(new Token(beginSymbol, Token.TYPE_AREA_SEPARATOR, level)));
69 |
70 | boolean first = true;
71 | for (JsonElement e : elements)
72 | {
73 | if (!first)
74 | {
75 | iters.add(new SimpleIterator(new Token("" + NEXT_SEPARATOR, Token.TYPE_SEG_SEPARATOR, level + 1)));
76 | }
77 | else
78 | {
79 | first = false;
80 | }
81 |
82 | e.setLevel(level + 1);
83 | iters.add(e.iterator());
84 | }
85 |
86 | iters.add(new SimpleIterator(new Token(endSymbol, Token.TYPE_AREA_SEPARATOR, level)));
87 | }
88 |
89 | @Override
90 | public boolean hasNext()
91 | {
92 | while (elementIdx < iters.size())
93 | {
94 | if (iters.get(elementIdx).hasNext())
95 | {
96 | return true;
97 | }
98 | elementIdx++;
99 | }
100 |
101 | return false;
102 | }
103 |
104 | @Override
105 | public Token next()
106 | {
107 | while (elementIdx < iters.size())
108 | {
109 | Token t = iters.get(elementIdx).next();
110 | if (t != null)
111 | {
112 | return t;
113 | }
114 | elementIdx++;
115 | }
116 |
117 | return null;
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/element/JsonBoolean.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.element;
2 |
3 | import java.util.Iterator;
4 |
5 | /**
6 | * @author zgwangbo@simplemain.com
7 | */
8 | public class JsonBoolean extends JsonElement
9 | {
10 | public static final String TRUE = "true";
11 | public static final String FALSE = "false";
12 |
13 | private final String string;
14 |
15 | public static JsonBoolean createTrue()
16 | {
17 | return new JsonBoolean("true");
18 | }
19 |
20 | public static JsonBoolean createFalse()
21 | {
22 | return new JsonBoolean("false");
23 | }
24 |
25 | private JsonBoolean(String s)
26 | {
27 | this.string = s;
28 | }
29 |
30 | public String toString()
31 | {
32 | return string;
33 | }
34 |
35 | @Override
36 | public Iterator iterator()
37 | {
38 | return new SimpleIterator(new Token(string, Token.TYPE_KEYWORD, level));
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/element/JsonElement.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.element;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Iterator;
5 | import java.util.List;
6 |
7 | import com.simplemain.kit.json.error.SyntaxException;
8 |
9 | /**
10 | * @author zgwangbo@simplemain.com
11 | */
12 | public abstract class JsonElement implements Iterable
13 | {
14 | protected int level;
15 | protected List exceptions = new ArrayList<>();
16 |
17 | public abstract Iterator iterator();
18 |
19 | protected class SimpleIterator implements Iterator
20 | {
21 | private Token token;
22 |
23 | SimpleIterator(Token token)
24 | {
25 | this.token = token;
26 | if (token != null)
27 | {
28 | token.exceptions = exceptions;
29 | }
30 | }
31 |
32 | @Override
33 | public boolean hasNext()
34 | {
35 | return token != null;
36 | }
37 |
38 | @Override
39 | public Token next()
40 | {
41 | Token ret = token;
42 | token = null;
43 | return ret;
44 | }
45 | }
46 |
47 | public int getLevel()
48 | {
49 | return level;
50 | }
51 |
52 | public void setLevel(int level)
53 | {
54 | this.level = level;
55 | }
56 |
57 | public void addException(SyntaxException e)
58 | {
59 | exceptions.add(e);
60 | }
61 |
62 | public List getExceptions()
63 | {
64 | return exceptions;
65 | }
66 |
67 | public boolean hasExceptions()
68 | {
69 | return !exceptions.isEmpty();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/element/JsonNull.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.element;
2 |
3 | import java.util.Iterator;
4 |
5 | /**
6 | * @author zgwangbo@simplemain.com
7 | */
8 | public class JsonNull extends JsonElement
9 | {
10 | public static final String NULL = "null";
11 |
12 | public String toString()
13 | {
14 | return NULL;
15 | }
16 |
17 | @Override
18 | public Iterator iterator()
19 | {
20 | return new SimpleIterator(new Token(toString(), Token.TYPE_KEYWORD, level));
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/element/JsonNumber.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.element;
2 |
3 | import java.util.Iterator;
4 |
5 | /**
6 | * @author zgwangbo@simplemain.com
7 | */
8 | public class JsonNumber extends JsonElement
9 | {
10 | private String string;
11 |
12 | public JsonNumber(String s)
13 | {
14 | string = s;
15 | }
16 |
17 | public String toString()
18 | {
19 | return string;
20 | }
21 |
22 | @Override
23 | public Iterator iterator()
24 | {
25 | return new SimpleIterator(new Token(string, Token.TYPE_NUMBER, level));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/element/JsonObject.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.element;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Iterator;
5 | import java.util.List;
6 |
7 | /**
8 | * @author zgwangbo@simplemain.com
9 | */
10 | public class JsonObject extends JsonElement
11 | {
12 | public static final char BEGIN_SYMBOL = '{';
13 | public static final char END_SYMBOL = '}';
14 | public static final char KV_SEPARATOR = ':';
15 | public static final char NEXT_SEPARATOR = ',';
16 |
17 | private static class Pair
18 | {
19 | JsonString key;
20 | String sep;
21 | JsonElement value;
22 |
23 | Pair(JsonString key, String sep, JsonElement value)
24 | {
25 | this.key = key;
26 | this.sep = sep;
27 | this.value = value;
28 | }
29 | }
30 |
31 | private List list = new ArrayList<>();
32 |
33 | private String beginSymbol = "";
34 | private String endSymbol = "";
35 |
36 | public void fillBeginSymbol()
37 | {
38 | beginSymbol = "" + BEGIN_SYMBOL;
39 | }
40 |
41 | public void fillEndSymbol()
42 | {
43 | endSymbol = "" + END_SYMBOL;
44 | }
45 |
46 | public void add(JsonString key, String sep, JsonElement value)
47 | {
48 | list.add(new Pair(key, sep, value));
49 | }
50 |
51 | public void add(IllegalElement ie)
52 | {
53 | list.add(new Pair(null, null, ie));
54 | }
55 |
56 | @Override
57 | public String toString()
58 | {
59 | StringBuffer sb = new StringBuffer();
60 | boolean first = true;
61 | for (Pair p : list)
62 | {
63 | if (!first)
64 | {
65 | sb.append(NEXT_SEPARATOR + " ");
66 | }
67 | else
68 | {
69 | first = false;
70 | }
71 | sb.append(p.key + " " + KV_SEPARATOR + " " + p.value);
72 | }
73 | return beginSymbol + sb.toString() + endSymbol;
74 | }
75 |
76 | @Override
77 | public Iterator iterator()
78 | {
79 | return new DefaultIterator();
80 | }
81 |
82 | private class DefaultIterator implements Iterator
83 | {
84 | protected List> iters = new ArrayList<>();
85 |
86 | protected int elementIdx = 0;
87 |
88 | DefaultIterator()
89 | {
90 | iters.add(new SimpleIterator(new Token("" + beginSymbol, Token.TYPE_AREA_SEPARATOR, level)));
91 |
92 | boolean first = true;
93 | for (Pair p : list)
94 | {
95 | if (!first)
96 | {
97 | if (p.key != null && p.value != null)
98 | {
99 | iters.add(new SimpleIterator(new Token("" + NEXT_SEPARATOR, Token.TYPE_SEG_SEPARATOR, level + 1)));
100 | }
101 | }
102 | else
103 | {
104 | first = false;
105 | }
106 |
107 | if (p.key != null)
108 | {
109 | p.key.setLevel(level + 1);
110 | iters.add(p.key.iterator());
111 | }
112 |
113 | if (p.sep != null)
114 | {
115 | iters.add(new SimpleIterator(new Token(p.sep, Token.TYPE_KV_SEPARATOR, level + 1)));
116 | }
117 |
118 | if (p.value != null)
119 | {
120 | p.value.setLevel(level + 1);
121 | iters.add(p.value.iterator());
122 | }
123 | }
124 |
125 | iters.add(new SimpleIterator(new Token("" + endSymbol, Token.TYPE_AREA_SEPARATOR, level)));
126 | }
127 |
128 | @Override
129 | public boolean hasNext()
130 | {
131 | while (elementIdx < iters.size())
132 | {
133 | if (iters.get(elementIdx).hasNext())
134 | {
135 | return true;
136 | }
137 | elementIdx++;
138 | }
139 |
140 | return false;
141 | }
142 |
143 | @Override
144 | public Token next()
145 | {
146 | while (elementIdx < iters.size())
147 | {
148 | Token t = iters.get(elementIdx).next();
149 | if (t != null)
150 | {
151 | return t;
152 | }
153 | elementIdx++;
154 | }
155 |
156 | return null;
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/element/JsonString.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.element;
2 |
3 | import java.util.Iterator;
4 |
5 | /**
6 | * @author zgwangbo@simplemain.com
7 | */
8 | public class JsonString extends JsonElement
9 | {
10 | public static final char SIGN = '"';
11 | public static final char POSSIBLE_SIGN = '\'';
12 |
13 | private String string;
14 |
15 | private String beginSymbol = "";
16 | private String endSymbol = "";
17 |
18 | public JsonString()
19 | {
20 | }
21 |
22 | public JsonString(String s)
23 | {
24 | string = s;
25 | }
26 |
27 | public void fillBeginSymbol()
28 | {
29 | beginSymbol = "" + SIGN;
30 | }
31 |
32 | public void fillEndSymbol()
33 | {
34 | endSymbol = "" + SIGN;
35 | }
36 |
37 | public String toString()
38 | {
39 | return beginSymbol + string + endSymbol;
40 | }
41 |
42 | @Override
43 | public Iterator iterator()
44 | {
45 | return new SimpleIterator(new Token(toString(), Token.TYPE_STRING, level));
46 | }
47 |
48 | public String getString()
49 | {
50 | return string;
51 | }
52 |
53 | public void setString(String string)
54 | {
55 | this.string = string;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/element/Token.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.element;
2 |
3 | import java.util.List;
4 |
5 | import com.simplemain.kit.json.error.SyntaxException;
6 |
7 | /**
8 | * @author zgwangbo@simplemain.com
9 | */
10 | public class Token
11 | {
12 | private static int idx = 0;
13 |
14 | public static final int TYPE_NORAML = idx++;
15 | public static final int TYPE_KEYWORD = idx++;
16 | public static final int TYPE_AREA_SEPARATOR = idx++;
17 | public static final int TYPE_KV_SEPARATOR = idx++;
18 | public static final int TYPE_SEG_SEPARATOR = idx++;
19 | public static final int TYPE_NUMBER = idx++;
20 | public static final int TYPE_STRING = idx++;
21 |
22 | public static final int TYPE_ILLEGAL = idx++;
23 |
24 | private String value;
25 | private int type;
26 | private int level;
27 | List exceptions;
28 |
29 | public Token() {}
30 |
31 | public Token(String value, int type, int level)
32 | {
33 | this.value = value;
34 | this.type = type;
35 | this.level = level;
36 | }
37 |
38 | public String getValue()
39 | {
40 | return value;
41 | }
42 |
43 | public void setValue(String value)
44 | {
45 | this.value = value;
46 | }
47 |
48 | public int getType()
49 | {
50 | return type;
51 | }
52 |
53 | public void setType(int type)
54 | {
55 | this.type = type;
56 | }
57 |
58 | public int getLevel()
59 | {
60 | return level;
61 | }
62 |
63 | public void setLevel(int level)
64 | {
65 | this.level = level;
66 | }
67 |
68 | public List getExceptions()
69 | {
70 | return exceptions;
71 | }
72 |
73 | public boolean hasExceptions()
74 | {
75 | return !exceptions.isEmpty();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/error/SyntaxError.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.error;
2 |
3 | /**
4 | * @author zgwangbo@simplemain.com
5 | */
6 | public class SyntaxError extends SyntaxException
7 | {
8 | private static final long serialVersionUID = -4674194378872598782L;
9 |
10 | public SyntaxError(String msg)
11 | {
12 | super(msg, TYPE_ERROR);
13 | }
14 |
15 | public SyntaxError(int lineNo, int rowNo, String nearByString, String msg)
16 | {
17 | super(lineNo, rowNo, nearByString, msg, TYPE_ERROR);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/error/SyntaxException.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.error;
2 |
3 | /**
4 | * @author zgwangbo@simplemain.com
5 | */
6 | public abstract class SyntaxException extends RuntimeException
7 | {
8 | private static final long serialVersionUID = 1230377296133173902L;
9 |
10 | protected static final String TYPE_WARN = "warning";
11 | protected static final String TYPE_ERROR = "error";
12 |
13 | protected int lineNo;
14 | protected int rowNo;
15 | protected String nearByString;
16 | protected String type;
17 |
18 | public SyntaxException(String msg, String type)
19 | {
20 | this(0, 0, null, msg, type);
21 | }
22 |
23 | public SyntaxException(int lineNo, int rowNo, String nearByString, String msg, String type)
24 | {
25 | super(msg);
26 | this.lineNo = lineNo;
27 | this.rowNo = rowNo;
28 | this.nearByString = nearByString;
29 | this.type = type;
30 | }
31 |
32 | public int getLineNo()
33 | {
34 | return lineNo;
35 | }
36 |
37 | public int getRowNo()
38 | {
39 | return rowNo;
40 | }
41 |
42 | public String toString()
43 | {
44 | return String.format("syntax %s at [%d:%d] near [%s] caused by [%s]",
45 | type, lineNo, rowNo, nearByString, super.getMessage());
46 | }
47 |
48 | public String getNearByString()
49 | {
50 | return nearByString;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/error/SyntaxWarning.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.error;
2 |
3 | /**
4 | * @author zgwangbo@simplemain.com
5 | */
6 | public class SyntaxWarning extends SyntaxException
7 | {
8 | private static final long serialVersionUID = -4674194398872598782L;
9 |
10 | public SyntaxWarning(String msg)
11 | {
12 | super(msg, TYPE_WARN);
13 | }
14 |
15 | public SyntaxWarning(int lineNo, int rowNo, String nearByString, String msg)
16 | {
17 | super(lineNo, rowNo, nearByString, msg, TYPE_WARN);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/format/JsonFormatter.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.format;
2 |
3 | /**
4 | * @author zgwangbo@simplemain.com
5 | */
6 | import java.io.PrintWriter;
7 |
8 | import com.simplemain.kit.json.element.JsonElement;
9 |
10 | public interface JsonFormatter
11 | {
12 | public void format(JsonElement element, PrintWriter pw);
13 | }
14 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/format/MetaFormatter.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.format;
2 |
3 | import java.io.PrintWriter;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | import com.simplemain.kit.json.element.JsonElement;
8 | import com.simplemain.kit.json.element.Token;
9 | import com.simplemain.kit.json.error.SyntaxException;
10 |
11 | public class MetaFormatter implements JsonFormatter
12 | {
13 | private List lines = new ArrayList<>();
14 | private List exceptions = new ArrayList<>();
15 |
16 | @Override
17 | public void format(JsonElement element, PrintWriter pw)
18 | {
19 | if (element == null)
20 | {
21 | return;
22 | }
23 |
24 | Line currentLine = newLine();
25 |
26 | int lastLevel = 0;
27 |
28 | for (Token token : element)
29 | {
30 | int level = token.getLevel();
31 |
32 | if (level != lastLevel)
33 | {
34 | currentLine = newLine();
35 | lastLevel = level;
36 |
37 | currentLine.setTabCount(level);
38 | currentLine.getTokens().add(token);
39 | }
40 | else if (token.getType() == Token.TYPE_SEG_SEPARATOR)
41 | {
42 | currentLine.getTokens().add(token);
43 | currentLine = newLine();
44 | currentLine.setTabCount(level);
45 | }
46 | else
47 | {
48 | currentLine.getTokens().add(token);
49 | }
50 |
51 | if (token.hasExceptions())
52 | {
53 | for (SyntaxException e : token.getExceptions())
54 | {
55 | if (!currentLine.getExceptions().contains(e))
56 | {
57 | currentLine.getExceptions().add(e);
58 | }
59 |
60 | if (!exceptions.contains(e))
61 | {
62 | exceptions.add(e);
63 | }
64 | }
65 | }
66 | }
67 |
68 | }
69 |
70 | private Line newLine()
71 | {
72 | final Line line = new Line();
73 | lines.add(line);
74 | return line;
75 | }
76 |
77 | public static class Line
78 | {
79 | private int tabCount = 0;
80 | private List exceptions = new ArrayList<>();
81 | private List tokens = new ArrayList<>();
82 |
83 | public int getTabCount()
84 | {
85 | return tabCount;
86 | }
87 | public void setTabCount(int tabCount)
88 | {
89 | this.tabCount = tabCount;
90 | }
91 | public List getTokens()
92 | {
93 | return tokens;
94 | }
95 | public List getExceptions()
96 | {
97 | return exceptions;
98 | }
99 | }
100 |
101 | public List getLines()
102 | {
103 | return lines;
104 | }
105 |
106 | public List getExceptions()
107 | {
108 | return exceptions;
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/format/TextJsonFormatter.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.format;
2 |
3 | import java.io.PrintWriter;
4 | import java.util.List;
5 |
6 | import com.simplemain.kit.json.element.JsonElement;
7 | import com.simplemain.kit.json.element.Token;
8 | import com.simplemain.kit.json.error.SyntaxException;
9 | import com.simplemain.kit.json.format.MetaFormatter.Line;
10 |
11 | public class TextJsonFormatter implements JsonFormatter
12 | {
13 | private static final String TAB = " ";
14 |
15 | private boolean withLineNo = false; // 是否输出行号
16 | private boolean withErrorInline = false; // 是否在行内输出错误指示
17 | private boolean withErrorDetail = false; // 是否输出详细错误信息
18 |
19 | public TextJsonFormatter()
20 | {
21 | this(false, false, false);
22 | }
23 |
24 | public TextJsonFormatter(boolean withLineNo, boolean withErrorInline, boolean withErrorDetail)
25 | {
26 | this.withLineNo = withLineNo;
27 | this.withErrorInline = withErrorInline;
28 | this.withErrorDetail = withErrorDetail;
29 | }
30 |
31 | @Override
32 | public void format(JsonElement element, PrintWriter pw)
33 | {
34 | final MetaFormatter format = new MetaFormatter();
35 | format.format(element, pw);
36 |
37 | final List lines = format.getLines();
38 | final List exceptions = format.getExceptions();
39 |
40 | final int lineNoWidth = getLineNoWidth(lines.size());
41 | int lineNo = 0;
42 |
43 | for (Line line : lines)
44 | {
45 | lineNo++;
46 |
47 | // 打印行号
48 | if (withLineNo)
49 | {
50 | if (lineNoWidth > 0)
51 | {
52 | pw.print(String.format("%" + lineNoWidth + "d.", lineNo));
53 | }
54 | else
55 | {
56 | pw.print(lineNo + ".");
57 | }
58 | }
59 |
60 | // 行内打印出错
61 | if (withErrorInline && !line.getExceptions().isEmpty())
62 | {
63 | pw.print("=>");
64 | }
65 | else if (withLineNo || (withErrorInline && !exceptions.isEmpty()))
66 | {
67 | pw.print(" ");
68 | }
69 |
70 | // 打印前导空格
71 | for (int i = 0; i < line.getTabCount(); i++)
72 | {
73 | pw.print(TAB);
74 | }
75 |
76 | // 打印内容
77 | for (Token token : line.getTokens())
78 | {
79 | final String s = token.getValue();
80 | if (token.getType() == Token.TYPE_KV_SEPARATOR)
81 | {
82 | pw.print(" " + s + " ");
83 | }
84 | else
85 | {
86 | pw.print(s);
87 | }
88 | }
89 |
90 | pw.println();
91 | }
92 |
93 | // 打印完整错误信息
94 | if (withErrorDetail && !exceptions.isEmpty())
95 | {
96 | pw.println();
97 | pw.println("==== syntax warnings & errors ====");
98 | for (SyntaxException e : exceptions)
99 | {
100 | pw.println(e.toString());
101 | }
102 | }
103 | }
104 |
105 | private int getLineNoWidth(int totalLineNo)
106 | {
107 | int ret = 0;
108 | for (; totalLineNo > 0; totalLineNo /= 10)
109 | {
110 | ret++;
111 | }
112 | return ret;
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/parser/ArrayParser.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.parser;
2 |
3 | import com.simplemain.kit.json.element.IllegalElement;
4 | import com.simplemain.kit.json.element.JsonArray;
5 | import com.simplemain.kit.json.element.JsonElement;
6 | import com.simplemain.kit.json.error.SyntaxError;
7 |
8 | /**
9 | * @author zgwangbo@simplemain.com
10 | */
11 | public class ArrayParser implements ElementParser
12 | {
13 | @Override
14 | public JsonArray parse(Symbol symbol)
15 | {
16 | symbol.mark();
17 |
18 | final JsonArray ret = new JsonArray();
19 |
20 | final char begin = symbol.nextWithoutSpace();
21 | if (JsonArray.BEGIN_SYMBOL != begin)
22 | {
23 | symbol.reset();
24 | return null;
25 | }
26 | ret.fillBeginSymbol();
27 |
28 | for (boolean force = false; symbol.hasNext(); force = true)
29 | {
30 | symbol.mark();
31 |
32 | final ValueParser vp = new ValueParser();
33 | final JsonElement value = vp.parse(symbol);
34 | if (value == null)
35 | {
36 | if (force) // error
37 | {
38 | SyntaxError error = new SyntaxError(symbol.getLineNo(),
39 | symbol.getRowNo(),
40 | symbol.getNearByChars(),
41 | "in ARRAY, a valid value is needed after comma(,)");
42 |
43 | String remaining = symbol.getRemaining();
44 | IllegalElement ie = new IllegalElement(remaining, error);
45 | ret.add(ie);
46 | return ret;
47 | }
48 | else
49 | {
50 | symbol.reset();
51 | break;
52 | }
53 | }
54 |
55 | ret.add(value);
56 |
57 | symbol.mark();
58 | char next = symbol.nextWithoutSpace();
59 |
60 | if (JsonArray.NEXT_SEPARATOR != next)
61 | {
62 | symbol.reset();
63 | break;
64 | }
65 | }
66 |
67 | final char end = symbol.nextWithoutSpace();
68 | if (JsonArray.END_SYMBOL == end)
69 | {
70 | ret.fillEndSymbol();
71 | return ret;
72 | }
73 | else
74 | {
75 | symbol.reset();
76 |
77 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(),
78 | symbol.getNearByChars(), "in ARRAY, a right-bracket(]) is needed at the end");
79 |
80 | String remaining = symbol.getRemaining();
81 | IllegalElement ie = new IllegalElement(remaining, error);
82 | ret.add(ie);
83 | return ret;
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/parser/BooleanParser.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.parser;
2 |
3 | import com.simplemain.kit.json.element.JsonBoolean;
4 | import com.simplemain.kit.json.element.JsonElement;
5 |
6 | /**
7 | * @author zgwangbo@simplemain.com
8 | */
9 | public class BooleanParser implements ElementParser
10 | {
11 | @Override
12 | public JsonElement parse(Symbol symbol)
13 | {
14 | symbol.mark();
15 |
16 | StringBuffer sb = new StringBuffer();
17 | for (int i = 0; i < JsonBoolean.TRUE.length() && symbol.hasNext(); i++)
18 | {
19 | char ch = i == 0 ? symbol.nextWithoutSpace() : symbol.next();
20 | sb.append(ch);
21 | }
22 | String s = sb.toString();
23 | if (JsonBoolean.TRUE.compareToIgnoreCase(s) == 0)
24 | {
25 | return JsonBoolean.createTrue();
26 | }
27 |
28 | sb.append(symbol.next());
29 | s = sb.toString();
30 | if (JsonBoolean.FALSE.compareToIgnoreCase(s) == 0)
31 | {
32 | return JsonBoolean.createFalse();
33 | }
34 |
35 | symbol.reset();
36 |
37 | return null;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/parser/ElementParser.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.parser;
2 |
3 | import com.simplemain.kit.json.element.JsonElement;
4 |
5 | /**
6 | * @author zgwangbo@simplemain.com
7 | */
8 | public interface ElementParser
9 | {
10 | public JsonElement parse(Symbol symbol);
11 | }
12 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/parser/JsonParser.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.parser;
2 |
3 | import com.simplemain.kit.json.element.IllegalElement;
4 | import com.simplemain.kit.json.element.JsonElement;
5 | import com.simplemain.kit.json.element.Token;
6 | import com.simplemain.kit.json.error.SyntaxError;
7 |
8 | /**
9 | * @author zgwangbo@simplemain.com
10 | */
11 | public class JsonParser
12 | {
13 | private static final ElementParser[] PARSERS = {new ObjectParser(), new ArrayParser()};
14 |
15 | public JsonElement parse(String string)
16 | {
17 | return parse(string, false);
18 | }
19 |
20 | public JsonElement parse(String string, boolean throwsExceptions)
21 | {
22 | if (string == null || string.trim().equals(""))
23 | {
24 | return null;
25 | }
26 |
27 | final Symbol symbol = new Symbol(string);
28 |
29 | for (ElementParser parser : PARSERS)
30 | {
31 | final JsonElement je = parser.parse(symbol);
32 | if (je != null)
33 | {
34 | symbol.mark();
35 | if (symbol.nextWithoutSpace() != 0) // 结束符后不应该再出现内容
36 | {
37 | symbol.reset();
38 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(),
39 | symbol.getRemaining(), "unexpected characters!");
40 |
41 | je.addException(error);
42 | }
43 |
44 | if (throwsExceptions)
45 | {
46 | for (Token token : je)
47 | {
48 | if (token.hasExceptions())
49 | {
50 | throw token.getExceptions().get(0);
51 | }
52 | }
53 | }
54 |
55 | return je;
56 | }
57 | }
58 |
59 | SyntaxError error = new SyntaxError(1, 1, string, "parse error");
60 | if (throwsExceptions)
61 | {
62 | throw error;
63 | }
64 |
65 | String remaining = symbol.getRemaining();
66 | IllegalElement ie = new IllegalElement(remaining, error);
67 |
68 | return ie;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/parser/NullParser.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.parser;
2 |
3 | import com.simplemain.kit.json.element.JsonElement;
4 | import com.simplemain.kit.json.element.JsonNull;
5 |
6 | /**
7 | * @author zgwangbo@simplemain.com
8 | */
9 | public class NullParser implements ElementParser
10 | {
11 | @Override
12 | public JsonElement parse(Symbol symbol)
13 | {
14 | symbol.mark();
15 |
16 | StringBuffer sb = new StringBuffer();
17 | for (int i = 0; i < JsonNull.NULL.length() && symbol.hasNext(); i++)
18 | {
19 | char ch = i == 0 ? symbol.nextWithoutSpace() : symbol.next();
20 | sb.append(ch);
21 | }
22 |
23 | String s = sb.toString();
24 | if (JsonNull.NULL.compareToIgnoreCase(s) == 0)
25 | {
26 | return new JsonNull();
27 | }
28 |
29 | symbol.reset();
30 |
31 | return null;
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/parser/NumberParser.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.parser;
2 |
3 | import com.simplemain.kit.json.element.IllegalElement;
4 | import com.simplemain.kit.json.element.JsonElement;
5 | import com.simplemain.kit.json.element.JsonNumber;
6 | import com.simplemain.kit.json.error.SyntaxError;
7 |
8 | /**
9 | * @author zgwangbo@simplemain.com
10 | */
11 | public class NumberParser implements ElementParser
12 | {
13 | @Override
14 | public JsonElement parse(Symbol symbol)
15 | {
16 | StringBuffer sb = new StringBuffer();
17 |
18 | // 符号
19 | final String sign = getSign(symbol);
20 | if (sign != null)
21 | {
22 | sb.append(sign);
23 | }
24 | boolean hasSign = sign != null;
25 |
26 | // 整数部分
27 | final String intPart = getIntegerPart(symbol, hasSign);
28 | if (intPart != null)
29 | {
30 | sb.append(intPart);
31 | }
32 | else
33 | {
34 | if (hasSign) // 出错
35 | {
36 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(),
37 | symbol.getNearByChars(), "in NUMBER, expect DIGIT after minus(-)");
38 |
39 | IllegalElement ie = new IllegalElement(sb.toString(), error);
40 | return ie;
41 |
42 | // return null;
43 | }
44 | else
45 | {
46 | symbol.reset();
47 | return null;
48 | }
49 | }
50 |
51 | // 小数部分
52 | final String decimalPart = getDecimalPart(symbol);
53 | if (decimalPart != null)
54 | {
55 | sb.append(decimalPart);
56 | }
57 |
58 | // 指数部分
59 | final String exponentPart = getExponentPart(symbol);
60 | if (exponentPart != null)
61 | {
62 | sb.append(exponentPart);
63 | }
64 |
65 | if (sb.length() == 0)
66 | {
67 | return null;
68 | }
69 |
70 | JsonNumber ret = new JsonNumber(sb.toString());
71 |
72 | return ret;
73 | }
74 |
75 | private String getExponentPart(Symbol symbol)
76 | {
77 | StringBuffer sb = new StringBuffer();
78 |
79 | symbol.mark();
80 | char ch = symbol.next();
81 |
82 | if ('e' == Character.toLowerCase(ch))
83 | {
84 | sb.append(ch);
85 | symbol.mark();
86 | ch = symbol.next();
87 | if ('+' == ch || '-' == ch)
88 | {
89 | sb.append(ch);
90 | }
91 | else
92 | {
93 | symbol.reset();
94 | }
95 |
96 | ch = symbol.next();
97 | if (!Character.isDigit(ch))
98 | {
99 | throw new RuntimeException();
100 | }
101 | sb.append(ch);
102 |
103 | while (symbol.hasNext())
104 | {
105 | symbol.mark();
106 | ch = symbol.next();
107 | if (!Character.isDigit(ch))
108 | {
109 | symbol.reset();
110 | break;
111 | }
112 | sb.append(ch);
113 | }
114 |
115 | return sb.toString();
116 | }
117 | else
118 | {
119 | symbol.reset();
120 | return null;
121 | }
122 | }
123 |
124 | private String getSign(Symbol symbol)
125 | {
126 | symbol.mark();
127 | char ch = symbol.nextWithoutSpace();
128 | if (ch == '-')
129 | {
130 | return "" + ch;
131 | }
132 | symbol.reset();
133 | return null;
134 | }
135 |
136 | private String getIntegerPart(Symbol symbol, boolean hasSign)
137 | {
138 | StringBuffer sb = new StringBuffer();
139 |
140 | symbol.mark();
141 | char ch = hasSign ? symbol.next() : symbol.nextWithoutSpace();
142 |
143 | if (ch == '0')
144 | {
145 | sb.append(ch);
146 | }
147 | else if (ch >= '1' && ch <= '9')
148 | {
149 | sb.append(ch);
150 | while (symbol.hasNext())
151 | {
152 | symbol.mark();
153 | ch = symbol.next();
154 | if (!Character.isDigit(ch))
155 | {
156 | symbol.reset();
157 | break;
158 | }
159 | sb.append(ch);
160 | }
161 | }
162 | else
163 | {
164 | symbol.reset();
165 | return null;
166 | }
167 |
168 | return sb.toString();
169 | }
170 |
171 | private String getDecimalPart(Symbol symbol)
172 | {
173 | StringBuffer sb = new StringBuffer();
174 |
175 | symbol.mark();
176 | char ch = symbol.next();
177 | if ('.' == ch)
178 | {
179 | sb.append(ch);
180 | ch = symbol.next();
181 | if (!Character.isDigit(ch))
182 | {
183 | throw new RuntimeException();
184 | }
185 | sb.append(ch);
186 |
187 | while (symbol.hasNext())
188 | {
189 | symbol.mark();
190 | ch = symbol.next();
191 | if (!Character.isDigit(ch))
192 | {
193 | symbol.reset();
194 | break;
195 | }
196 | sb.append(ch);
197 | }
198 | return sb.toString();
199 | }
200 | else
201 | {
202 | symbol.reset();
203 | return null;
204 | }
205 | }
206 |
207 | public static void main(String[] args)
208 | {
209 | String[] numbers = {"12345", "-123", "123.4", "123.456", "0.123", "0.012", "123E12", "123.23e10"};
210 |
211 | NumberParser p = new NumberParser();
212 | for (String num : numbers)
213 | {
214 | JsonElement jn = p.parse(new Symbol(num));
215 | System.out.println(num.equalsIgnoreCase(jn.toString()) + " : " + num + " ==> " + jn);
216 | }
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/parser/ObjectParser.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.parser;
2 |
3 | import com.simplemain.kit.json.element.IllegalElement;
4 | import com.simplemain.kit.json.element.JsonElement;
5 | import com.simplemain.kit.json.element.JsonObject;
6 | import com.simplemain.kit.json.element.JsonString;
7 | import com.simplemain.kit.json.error.SyntaxError;
8 |
9 | /**
10 | * @author zgwangbo@simplemain.com
11 | */
12 | public class ObjectParser implements ElementParser
13 | {
14 | @Override
15 | public JsonObject parse(Symbol symbol)
16 | {
17 | symbol.mark();
18 |
19 | final JsonObject ret = new JsonObject();
20 |
21 | final char begin = symbol.nextWithoutSpace();
22 | if (JsonObject.BEGIN_SYMBOL != begin)
23 | {
24 | symbol.reset();
25 | return null;
26 | }
27 | ret.fillBeginSymbol();
28 |
29 | for (boolean force = false; symbol.hasNext(); force = true)
30 | {
31 | symbol.mark();
32 |
33 | final StringParser sp = new StringParser();
34 | final JsonString key = sp.parse(symbol);
35 | if (key == null)
36 | {
37 | if (force) // error
38 | {
39 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(),
40 | symbol.getNearByChars(), "in OBJECT, a STRING key is needed");
41 |
42 | String remaining = symbol.getRemaining();
43 | IllegalElement ie = new IllegalElement(remaining, error);
44 | ret.add(ie);
45 | return ret;
46 | }
47 | else
48 | {
49 | symbol.reset();
50 | break;
51 | }
52 | }
53 |
54 | symbol.mark();
55 | char next = symbol.nextWithoutSpace();
56 |
57 | if (JsonObject.KV_SEPARATOR != next) // error
58 | {
59 | symbol.reset();
60 |
61 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(),
62 | symbol.getNearByChars(), "in OBJECT, a colon(:) is needed after key");
63 |
64 | String remaining = symbol.getRemaining();
65 | IllegalElement ie = new IllegalElement(remaining, error);
66 | ret.add(key, null, ie);
67 | return ret;
68 | }
69 |
70 | final ValueParser vp = new ValueParser();
71 | final JsonElement value = vp.parse(symbol);
72 | if (value == null) // error
73 | {
74 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(),
75 | symbol.getNearByChars(), "in OBJECT, a valid value is needed after the colon");
76 |
77 | String remaining = symbol.getRemaining();
78 | IllegalElement ie = new IllegalElement(remaining, error);
79 | ret.add(key, "" + JsonObject.KV_SEPARATOR, ie);
80 | return ret;
81 | }
82 |
83 | ret.add(key, "" + JsonObject.KV_SEPARATOR, value);
84 |
85 | symbol.mark();
86 | next = symbol.nextWithoutSpace();
87 |
88 | if (JsonObject.NEXT_SEPARATOR != next)
89 | {
90 | symbol.reset();
91 | break;
92 | }
93 | }
94 |
95 | final char end = symbol.nextWithoutSpace();
96 | if (JsonObject.END_SYMBOL == end)
97 | {
98 | ret.fillEndSymbol();
99 | return ret;
100 | }
101 | else
102 | {
103 | symbol.reset();
104 |
105 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(),
106 | symbol.getNearByChars(), "in OBJECT, a right-brace(}) is needed at the end");
107 |
108 | String remaining = symbol.getRemaining();
109 | IllegalElement ie = new IllegalElement(remaining, error);
110 | ret.add(ie);
111 | return ret;
112 | }
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/parser/StringParser.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.parser;
2 |
3 | import com.simplemain.kit.json.element.JsonString;
4 | import com.simplemain.kit.json.error.SyntaxError;
5 | import com.simplemain.kit.json.error.SyntaxWarning;
6 |
7 | /**
8 | * @author zgwangbo@simplemain.com
9 | */
10 | public class StringParser implements ElementParser
11 | {
12 | @Override
13 | public JsonString parse(Symbol symbol)
14 | {
15 | final JsonString ret = new JsonString();
16 |
17 | char ch = 0;
18 |
19 | symbol.mark();
20 |
21 | ch = symbol.nextWithoutSpace();
22 |
23 | char END = JsonString.SIGN;
24 | if (JsonString.SIGN == ch)
25 | {
26 |
27 | }
28 | else if (JsonString.POSSIBLE_SIGN == ch)
29 | {
30 | SyntaxWarning warn = new SyntaxWarning(symbol.getLineNo(), symbol.getRowNo(),
31 | symbol.getNearByChars(), "in STRING, \"'\" is NOT permitted");
32 |
33 | ret.addException(warn);
34 |
35 | END = JsonString.POSSIBLE_SIGN;
36 | }
37 | else
38 | {
39 | symbol.reset();
40 | return null;
41 | }
42 | ret.fillBeginSymbol();
43 |
44 |
45 | StringBuffer sb = new StringBuffer();
46 | while (symbol.hasNext())
47 | {
48 | ch = symbol.next();
49 | if (END == ch)
50 | {
51 | ret.setString(sb.toString());
52 | ret.fillEndSymbol();
53 | return ret;
54 | }
55 | else if ('\\' == ch)
56 | {
57 | // check : " \ / b f n r t uxxxx
58 | // sb.append(next);
59 | char next = symbol.next();
60 |
61 | if (next != 'u')
62 | {
63 | sb.append(ch);
64 | sb.append(next);
65 | }
66 |
67 | if (next == '"' || next == '\\' || next == 'b' || next == 'f' ||
68 | next == 'n' || next == 'r' || next == 't')
69 | {
70 | // permit
71 | }
72 | else if (next == 'u')
73 | {
74 | int num = 0;
75 | boolean hasError = false;
76 | String tmp = "" + ch + next;
77 | for (int i = 0; i < 4; i++)
78 | {
79 | next = symbol.next();
80 | next = Character.toLowerCase(next);
81 | tmp += next;
82 |
83 | if (next >= '0' && next <= '9' ||
84 | next >= 'a' && next <= 'f')
85 | {
86 | num *= 16;
87 | num += Integer.valueOf("" + next, 16);
88 | }
89 | else // error
90 | {
91 | SyntaxWarning warn = new SyntaxWarning(symbol.getLineNo(), symbol.getRowNo(),
92 | symbol.getNearByChars(), "in STRING, only [0-9a-fA-F] are permitted after \\u");
93 |
94 | ret.addException(warn);
95 | hasError = true;
96 | }
97 | }
98 |
99 | if (!hasError)
100 | {
101 | char c = (char)num;
102 | sb.append(c);
103 | }
104 | else
105 | {
106 | sb.append(tmp);
107 | }
108 | }
109 | else
110 | {
111 | SyntaxWarning warn = new SyntaxWarning(symbol.getLineNo(), symbol.getRowNo(),
112 | symbol.getNearByChars(), "in STRING, only [\\/bfnrtu] are permitted after \\");
113 |
114 | ret.addException(warn);
115 | }
116 | }
117 | else
118 | {
119 | sb.append(ch);
120 | }
121 | }
122 |
123 | ret.setString(sb.toString());
124 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(),
125 | symbol.getNearByChars(), "in STRING, a quote(\") is need at the end");
126 |
127 | ret.addException(error);
128 | return ret;
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/parser/Symbol.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.parser;
2 |
3 | import java.nio.CharBuffer;
4 |
5 | /**
6 | * @author zgwangbo@simplemain.com
7 | */
8 | public class Symbol
9 | {
10 | private static final int NEAR_BY_MAX_LEN = 10;
11 |
12 | private final String string;
13 | private final CharBuffer buffer;
14 |
15 | private int lineNo = 1;
16 | private int rowNo = 0;
17 | private int position = 0;
18 |
19 | private int markedLineNo = 0;
20 | private int markedRowNo = 0;
21 |
22 | public Symbol(String string)
23 | {
24 | this.string = string;
25 | this.buffer = CharBuffer.wrap(this.string);
26 | }
27 |
28 | public void mark()
29 | {
30 | buffer.mark();
31 | markedLineNo = lineNo;
32 | markedRowNo = rowNo;
33 | }
34 |
35 | public void reset()
36 | {
37 | buffer.reset();
38 |
39 | lineNo = markedLineNo;
40 | rowNo = markedRowNo;
41 | position = buffer.position();
42 | }
43 |
44 | public boolean hasNext()
45 | {
46 | return buffer.hasRemaining();
47 | }
48 |
49 | private boolean isNewLine(char ch)
50 | {
51 | return ch == '\n';
52 | }
53 |
54 | public char next()
55 | {
56 | char ret = buffer.hasRemaining() ? buffer.get() : 0;
57 | if (isNewLine(ret))
58 | {
59 | lineNo++;
60 | rowNo = 0;
61 | }
62 | else
63 | {
64 | rowNo++;
65 | }
66 | position = buffer.position();
67 |
68 | return ret;
69 | }
70 |
71 | public String getRemaining()
72 | {
73 | StringBuffer sb = new StringBuffer();
74 | while (hasNext())
75 | {
76 | sb.append(next());
77 | }
78 | return sb.toString();
79 | }
80 |
81 | public char nextWithoutSpace()
82 | {
83 | while (true)
84 | {
85 | if (!buffer.hasRemaining())
86 | {
87 | return 0;
88 | }
89 | char ch = buffer.get();
90 |
91 | if (isNewLine(ch))
92 | {
93 | lineNo++;
94 | rowNo = 0;
95 | }
96 | else
97 | {
98 | rowNo++;
99 | }
100 | position = buffer.position();
101 |
102 | if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
103 | {
104 | continue;
105 | }
106 |
107 | return ch;
108 | }
109 | }
110 |
111 | public int getLineNo()
112 | {
113 | return lineNo;
114 | }
115 |
116 | public int getRowNo()
117 | {
118 | return rowNo;
119 | }
120 |
121 | public String getNearByChars()
122 | {
123 | final int start = Math.max(position - NEAR_BY_MAX_LEN, 0);
124 | final int end = Math.min(position + NEAR_BY_MAX_LEN, string.length());
125 |
126 | if (start >= end)
127 | {
128 | return null;
129 | }
130 |
131 | return string.substring(start, end);
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/java/com/simplemain/kit/json/parser/ValueParser.java:
--------------------------------------------------------------------------------
1 | package com.simplemain.kit.json.parser;
2 |
3 | import com.simplemain.kit.json.element.JsonElement;
4 |
5 | /**
6 | * @author zgwangbo@simplemain.com
7 | */
8 | public class ValueParser implements ElementParser
9 | {
10 | private static final ElementParser[] PARSERS =
11 | {
12 | new StringParser(),
13 | new NumberParser(),
14 | new BooleanParser(),
15 | new NullParser(),
16 | new ObjectParser(),
17 | new ArrayParser(),
18 | };
19 |
20 | @Override
21 | public JsonElement parse(Symbol symbol)
22 | {
23 | for (ElementParser parser : PARSERS)
24 | {
25 | JsonElement je = parser.parse(symbol);
26 | if (je != null)
27 | {
28 | return je;
29 | }
30 | }
31 | return null;
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------