1 using System;
2
3 namespace Calculator
4 {
5 public inline bool IsNumberChar(uchar c)
6 {
7 return IsAsciiDigit(c) || c == '.';
8 }
9
10 public class Scanner
11 {
12 public Scanner(const ustring& input_) : input(input_)
13 {
14 }
15 public inline Token* CurrentToken() const
16 {
17 return token.Get();
18 }
19 public Result<bool> NextToken()
20 {
21 SkipWhiteSpace();
22 if (pos < input.Length())
23 {
24 if (IsNumberChar(input[pos]))
25 {
26 int start = pos;
27 ++pos;
28 while (pos < input.Length() && IsNumberChar(input[pos]))
29 {
30 ++pos;
31 }
32 auto utf8Result = ToUtf8(input.Substring(start, pos - start));
33 if (utf8Result.Error())
34 {
35 return Result<bool>(ErrorId(utf8Result.GetErrorId()));
36 }
37 auto parseResult = ParseDouble(utf8Result.Value());
38 if (parseResult.Error())
39 {
40 return Result<bool>(ErrorId(parseResult.GetErrorId()));
41 }
42 double number = parseResult.Value();
43 token.Reset(new NumberToken(number));
44 }
45 else
46 {
47 auto idStartResult = IsIdStart(input[pos]);
48 if (idStartResult.Error())
49 {
50 return idStartResult;
51 }
52 bool isIdStart = idStartResult.Value();
53 if (isIdStart)
54 {
55 int start = pos;
56 ++pos;
57 bool isIdCont = true;
58 while (pos < input.Length() && isIdCont)
59 {
60 auto idContResult = IsIdCont(input[pos]);
61 if (idContResult.Error())
62 {
63 return idContResult;
64 }
65 isIdCont = idContResult.Value();
66 if (isIdCont)
67 {
68 ++pos;
69 }
70 }
71 ustring variableName = input.Substring(start, pos - start);
72 auto toLowerResult = ToLower(variableName);
73 if (toLowerResult.Error())
74 {
75 return Result<bool>(ErrorId(toLowerResult.GetErrorId()));
76 }
77 ustring lower = toLowerResult.Value();
78 if (lower == u"print")
79 {
80 token.Reset(new PrintToken());
81 }
82 else
83 {
84 token.Reset(new VariableNameToken(variableName));
85 }
86 }
87 else
88 {
89 token.Reset(new OperatorToken(input[pos]));
90 ++pos;
91 }
92 }
93 }
94 else
95 {
96 token.Reset(new EndToken());
97 }
98 return Result<bool>(true);
99 }
100 public void Rewind()
101 {
102 pos = 0;
103 }
104 private void SkipWhiteSpace()
105 {
106 while (pos < input.Length() && (input[pos] == ' ' || input[pos] == '\t'))
107 {
108 ++pos;
109 }
110 }
111 private UniquePtr<Token> token;
112 private ustring input;
113 private int pos;
114 }