-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathinterp.rb
168 lines (135 loc) · 4.29 KB
/
interp.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
require "minruby"
# An implementation of the evaluator
def evaluate(exp, env)
# exp: A current node of AST
# env: An environment (explained later)
case exp[0]
#
## Problem 1: Arithmetics
#
when "lit"
exp[1] # return the immediate value as is
when "+"
evaluate(exp[1], env) + evaluate(exp[2], env)
when "-"
# Subtraction. Please fill in.
# Use the code above for addition as a reference.
# (Almost just copy-and-paste. This is an exercise.)
raise(NotImplementedError) # Problem 1
when "*"
raise(NotImplementedError) # Problem 1
# ... Implement other operators that you need
#
## Problem 2: Statements and variables
#
when "stmts"
# Statements: sequential evaluation of one or more expressions.
#
# Advice 1: Insert `pp(exp)` and observe the AST first.
# Advice 2: Apply `evaluate` to each child of this node.
raise(NotImplementedError) # Problem 2
# The second argument of this method, `env`, is an "environement" that
# keeps track of the values stored to variables.
# It is a Hash object whose key is a variable name and whose value is a
# value stored to the corresponded variable.
when "var_ref"
# Variable reference: lookup the value corresponded to the variable
#
# Advice: env[???]
raise(NotImplementedError) # Problem 2
when "var_assign"
# Variable assignment: store (or overwrite) the value to the environment
#
# Advice: env[???] = ???
raise(NotImplementedError) # Problem 2
#
## Problem 3: Branchs and loops
#
when "if"
# Branch. It evaluates either exp[2] or exp[3] depending upon the
# evaluation result of exp[1],
#
# Advice:
# if ???
# ???
# else
# ???
# end
raise(NotImplementedError) # Problem 3
when "while"
# Loop.
raise(NotImplementedError) # Problem 3
#
## Problem 4: Function calls
#
when "func_call"
# Lookup the function definition by the given function name.
func = $function_definitions[exp[1]]
if func.nil?
# We couldn't find a user-defined function definition;
# it should be a builtin function.
# Dispatch upon the given function name, and do paticular tasks.
case exp[1]
when "p"
# MinRuby's `p` method is implemented by Ruby's `p` method.
p(evaluate(exp[2], env))
# ... Problem 4
else
raise("unknown builtin function")
end
else
#
## Problem 5: Function definition
#
# (You may want to implement "func_def" first.)
#
# Here, we could find a user-defined function definition.
# The variable `func` should be a value that was stored at "func_def":
# a parameter list and an AST of function body.
#
# A function call evaluates the AST of function body within a new scope.
# You know, you cannot access a varible out of function.
# Therefore, you need to create a new environment, and evaluate the
# function body under the environment.
#
# Note, you can access formal parameters (*1) in function body.
# So, the new environment must be initialized with each parameter.
#
# (*1) formal parameter: a variable as found in the function definition.
# For example, `a`, `b`, and `c` are the formal parameters of
# `def foo(a, b, c)`.
raise(NotImplementedError) # Problem 5
end
when "func_def"
# Function definition.
#
# Add a new function definition to function definition list.
# The AST of "func_def" contains function name, parameter list, and the
# child AST of function body.
# All you need is store them into $function_definitions.
#
# Advice: $function_definitions[???] = ???
raise(NotImplementedError) # Problem 5
#
## Problem 6: Arrays and Hashes
#
# You don't need advices anymore, do you?
when "ary_new"
raise(NotImplementedError) # Problem 6
when "ary_ref"
raise(NotImplementedError) # Problem 6
when "ary_assign"
raise(NotImplementedError) # Problem 6
when "hash_new"
raise(NotImplementedError) # Problem 6
else
p("error")
pp(exp)
raise("unknown node")
end
end
$function_definitions = {}
env = {}
# `minruby_load()` == `File.read(ARGV.shift)`
# `minruby_parse(str)` parses a program text given, and returns its AST
evaluate(minruby_parse(minruby_load()), env)