1 module parser;
2 
3 import pry.stream;
4 
5 alias Stream = SimpleStream!string;
6 
7 bool expr(ref Stream s, ref int val, ref Stream.Error err){
8 	int v;
9 	if(!term(s, v, err)){
10 		return false;
11 	}
12 	if(s.empty){
13 		val = v;
14 		return true;
15 	}
16 	switch(s.front){
17 	case '+':
18 		s.popFront();
19 		int v2;
20 		if(!expr(s, v2, err)){
21 			return false;
22 		}
23 		val = v + v2;
24 		return true;
25 	case '-':
26 		s.popFront();
27 		int v2;
28 		if(!expr(s, v2, err)){
29 			return false;
30 		}
31 		val = v - v2;
32 		return true;
33 	default:
34 		val = v;
35 		return true;
36 	}
37 }
38 
39 bool term(ref Stream s, ref int val, ref Stream.Error err){
40 	int v;
41 	if(!primary(s, v, err)){
42 		return false;
43 	}
44 	if(s.empty){
45 		val = v;
46 		return true;
47 	}
48 	switch(s.front){
49 	case '*':
50 		s.popFront();
51 		int v2;
52 		if(!term(s, v2, err)){
53 			return false;
54 		}
55 		val = v * v2;
56 		return true;
57 	case '/':
58 		s.popFront();
59 		int v2;
60 		if(!term(s, v2, err)){
61 			return false;
62 		}
63 		val = v * v2;
64 		return true;
65 	default:
66 		val = v;
67 		return true;
68 	}
69 }
70 
71 bool primary(ref Stream s, ref int val, ref Stream.Error err){
72 	import std.conv;
73 	if(s.empty){
74 		err = Stream.Error(s.location, "Unexpected end of stream");
75 		return false;
76 	}
77 	switch(s.front){
78 	case '0' : .. case '9':
79 		auto m = s.mark();
80 		do{
81 			s.popFront();
82 		}while(!s.empty && s.front >= '0' && s.front <= '9');
83 		val = to!int(s.slice(m));
84 		return true;
85 	case '(':
86 		s.popFront();
87 		if(!expr(s, val, err)){
88 			return false;
89 		}
90 		if(s.front != ')'){
91 			err = Stream.Error(s.location, "Expected ')'");
92 		}
93 		s.popFront();
94 		return true;
95 	default:
96 		err = Stream.Error(s.location, "Unrecognized token");
97 		return false;
98 	}
99 }