Skip to content

Commit 6287eae

Browse files
Create a_programming_languague_completejavascript.com.js
1 parent c94beaa commit 6287eae

File tree

1 file changed

+263
-0
lines changed

1 file changed

+263
-0
lines changed
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
function parseExpression(program) {
2+
program = skipSpace(program);
3+
var match, expr;
4+
if (match = /^"([^"]*)"/.exec(program))
5+
expr = {type: "value", value: match[1]};
6+
else if (match = /^\d+\b/.exec(program))
7+
expr = {type: "value", value: Number(match[0])};
8+
else if (match = /^[^\s(),"]+/.exec(program))
9+
expr = {type: "word", name: match[0]};
10+
else
11+
throw new SyntaxError("Unexpected syntax: " + program);
12+
13+
return parseApply(expr, program.slice(match[0].length));
14+
}
15+
/*
16+
function skipSpace(string) {
17+
var first = string.search(/\S/);
18+
if (first == -1) return "";
19+
return string.slice(first);
20+
}
21+
*/
22+
23+
// This is the old skipSpace. Modify it...
24+
function skipSpace(string) {
25+
while(true)
26+
{
27+
var first = string.search(/\S/);
28+
if (first == -1) return "";
29+
30+
string = string.slice(first);
31+
if(string[0] != '#') return string;
32+
33+
first = string.search(/\n/);
34+
string = string.slice(first);
35+
}
36+
}
37+
38+
function parseApply(expr, program) {
39+
program = skipSpace(program);
40+
if (program[0] != "(")
41+
return {expr: expr, rest: program};
42+
43+
program = skipSpace(program.slice(1));
44+
expr = {type: "apply", operator: expr, args: []};
45+
while (program[0] != ")") {
46+
var arg = parseExpression(program);
47+
expr.args.push(arg.expr);
48+
program = skipSpace(arg.rest);
49+
if (program[0] == ",")
50+
program = skipSpace(program.slice(1));
51+
else if (program[0] != ")")
52+
throw new SyntaxError("Expected ',' or ')'");
53+
}
54+
return parseApply(expr, program.slice(1));
55+
}
56+
57+
function parse(program) {
58+
var result = parseExpression(program);
59+
if (skipSpace(result.rest).length > 0)
60+
throw new SyntaxError("Unexpected text after program");
61+
return result.expr;
62+
}
63+
64+
//console.log(parse("+(a, 10, 11)"));
65+
// → {type: "apply",
66+
// operator: {type: "word", name: "+"},
67+
// args: [{type: "word", name: "a"},
68+
// {type: "value", value: 10}]}
69+
70+
function evaluate(expr, env) {
71+
switch(expr.type) {
72+
case "value":
73+
return expr.value;
74+
75+
case "word":
76+
if (expr.name in env)
77+
return env[expr.name];
78+
else
79+
throw new ReferenceError("Undefined variable: " +
80+
expr.name);
81+
case "apply":
82+
if (expr.operator.type == "word" &&
83+
expr.operator.name in specialForms)
84+
return specialForms[expr.operator.name](expr.args,
85+
env);
86+
var op = evaluate(expr.operator, env);
87+
if (typeof op != "function")
88+
throw new TypeError("Applying a non-function.");
89+
return op.apply(null, expr.args.map(function(arg) {
90+
return evaluate(arg, env);
91+
}));
92+
}
93+
}
94+
95+
var specialForms = Object.create(null);
96+
97+
specialForms["if"] = function(args, env) {
98+
if (args.length != 3)
99+
throw new SyntaxError("Bad number of args to if");
100+
101+
if (evaluate(args[0], env) !== false)
102+
return evaluate(args[1], env);
103+
else
104+
return evaluate(args[2], env);
105+
};
106+
107+
specialForms["while"] = function(args, env) {
108+
if (args.length != 2)
109+
throw new SyntaxError("Bad number of args to while");
110+
111+
while (evaluate(args[0], env) !== false)
112+
evaluate(args[1], env);
113+
114+
// Since undefined does not exist in Egg, we return false,
115+
// for lack of a meaningful result.
116+
return false;
117+
};
118+
119+
specialForms["do"] = function(args, env) {
120+
var value = false;
121+
args.forEach(function(arg) {
122+
value = evaluate(arg, env);
123+
});
124+
return value;
125+
};
126+
127+
specialForms["define"] = function(args, env) {
128+
if (args.length != 2 || args[0].type != "word")
129+
throw new SyntaxError("Bad use of define");
130+
var value = evaluate(args[1], env);
131+
env[args[0].name] = value;
132+
return value;
133+
};
134+
135+
specialForms["fun"] = function(args, env) {
136+
if (!args.length)
137+
throw new SyntaxError("Functions need a body");
138+
function name(expr) {
139+
if (expr.type != "word")
140+
throw new SyntaxError("Arg names must be words");
141+
return expr.name;
142+
}
143+
var argNames = args.slice(0, args.length - 1).map(name);
144+
var body = args[args.length - 1];
145+
146+
return function() {
147+
if (arguments.length != argNames.length)
148+
throw new TypeError("Wrong number of arguments");
149+
var localEnv = Object.create(env);
150+
for (var i = 0; i < arguments.length; i++)
151+
localEnv[argNames[i]] = arguments[i];
152+
return evaluate(body, localEnv);
153+
};
154+
};
155+
156+
specialForms["set"] = function(args, env) {
157+
if (args.length != 2 || args[0].type != "word")
158+
throw new SyntaxError("Bad use of define");
159+
var proto = Object.getPrototypeOf(env);
160+
var check = false;
161+
while(true) {
162+
if(proto == null) {
163+
if (!check) throw new ReferenceError('ReferenceError hehe');
164+
else break;
165+
}
166+
167+
var value = evaluate(args[1], env);
168+
if(args[0].name in proto) {
169+
env[args[0].name] = value;
170+
check = true;
171+
}
172+
173+
proto = Object.getPrototypeOf(proto);
174+
}
175+
};
176+
177+
var topEnv = Object.create(null);
178+
179+
topEnv["true"] = true;
180+
topEnv["false"] = false;
181+
182+
["+", "-", "*", "/", "==", "<", ">"].forEach(function(op) {
183+
topEnv[op] = new Function("a, b", "return a " + op + " b;");
184+
});
185+
186+
topEnv["print"] = function(value) {
187+
console.log(value);
188+
return value;
189+
};
190+
191+
topEnv["array"] = function(){
192+
return Array.prototype.slice.call(arguments, 0);
193+
}
194+
195+
topEnv["length"] = function(array){
196+
return array.length;
197+
}
198+
199+
topEnv["element"] = function(array, i){
200+
return array[i];
201+
}
202+
203+
var prog = parse("if(true, false, true)");
204+
console.log(evaluate(prog, topEnv));
205+
206+
function run() {
207+
var env = Object.create(topEnv);
208+
var program = Array.prototype.slice
209+
.call(arguments, 0).join("\n");
210+
return evaluate(parse(program), env);
211+
}
212+
213+
run("do(define(total, 0),",
214+
" define(count, 1),",
215+
" while(<(count, 11),",
216+
" do(define(total, +(total, count)),",
217+
" define(count, +(count, 1)))),",
218+
" print(total))");
219+
// → 55
220+
221+
run("do(define(plusOne, fun(a, +(a, 1))),",
222+
" print(plusOne(10)))");
223+
// → 11
224+
225+
run("do(define(pow, fun(base, exp,",
226+
" if(==(exp, 0),",
227+
" 1,",
228+
" *(base, pow(base, -(exp, 1)))))),",
229+
" print(pow(2, 10)))");
230+
// → 1024
231+
232+
// Modify these definitions...
233+
234+
run("do(define(sum, fun(array,",
235+
" do(define(i, 0),",
236+
" define(sum, 0),",
237+
" while(<(i, length(array)),",
238+
" do(define(sum, +(sum, element(array, i))),",
239+
" define(i, +(i, 1)))),",
240+
" sum))),",
241+
" print(sum(array(1, 2, 3))))");
242+
// → 6
243+
244+
run("do(define(f, fun(a, fun(b, +(a, b)))),",
245+
" print(f(4)(5)))");
246+
// → 9
247+
248+
console.log(parse("# hello\nx"));
249+
// → {type: "word", name: "x"}
250+
251+
console.log(parse("a # one\n # two\n()"));
252+
// → {type: "apply",
253+
// operator: {type: "word", name: "a"},
254+
// args: []}
255+
256+
run("do(define(x, 4),",
257+
" define(setx, fun(val, set(x, val))),",
258+
" setx(50),",
259+
" print(x))");
260+
// → 50
261+
262+
run("set(quux, true)");
263+
// → Some kind of ReferenceError

0 commit comments

Comments
 (0)