+28
-6
lox/interpreter.janet
+28
-6
lox/interpreter.janet
···
32
32
token (errorf "Unknown operator %q" token))
33
33
left right))
34
34
35
+
(defn- declare-var [name]
36
+
(setdyn name @[]))
37
+
38
+
(defn- set-var [name val]
39
+
(if-let [ref (dyn name)]
40
+
(do (array/clear ref) (array/push ref val))
41
+
(errorf "Undefined variable '%s'." name)))
42
+
43
+
(defn- get-var [name]
44
+
(if-let [@[val] (dyn name)]
45
+
val
46
+
(errorf "Undefined variable '%s'." name)))
47
+
35
48
(defn evaluate [expr]
36
49
(match expr
37
50
[:literal value] value
···
41
54
[:logical left op right] (case ((op :token) 0)
42
55
:or (if-let [left (evaluate left)] left (evaluate right))
43
56
:and (if-let [left (evaluate left)] (evaluate right) left))
44
-
(errorf "Unknown expression type %q" (expr 0))))
57
+
[:assign {:token [:ident name]} value] (set-var name (evaluate value))
58
+
[:variable {:token [:ident name]}] (get-var name)
59
+
[ty] (errorf "Unknown expression type %s" ty)
60
+
(errorf "Invalid expression %q" expr)))
45
61
46
62
(var execute nil)
47
63
48
64
(defn- execute-block [stmts]
49
-
(each stmt stmts (execute stmt)))
65
+
# open new scope
66
+
(with-dyns []
67
+
(each stmt stmts (execute stmt))))
50
68
51
69
(varfn execute [stmt]
52
70
(match stmt
53
71
[:print expr] (printf "%q" (evaluate expr))
54
-
[:expr expr] (xprintf (dyn :expr-out stderr) "%Q" (evaluate expr))
72
+
[:expr expr] (xprintf (dyn :expr-out @"") "%Q" (evaluate expr))
55
73
# [:return word value] (throw return)
56
74
[:if cond then else] (do
57
75
(cond
···
59
77
(not (nil? else)) (execute else)))
60
78
[:while cond body] (while (evaluate cond) (execute body))
61
79
[:block stmts] (execute-block stmts)
62
-
(errorf "Unknown statement type %q" (stmt 0))))
80
+
[:var {:token [:ident name]} init] (let [val (and init (evaluate init))]
81
+
(declare-var name)
82
+
(when init (set-var name val)))
83
+
[ty] (errorf "Unknown statement type %s" ty)
84
+
(errorf "Invalid statement %q" stmt)))
63
85
64
86
(defn interpret [stmts]
87
+
(setdyn :locals @{})
65
88
# TODO error handling
66
-
(each stmt stmts (try (execute stmt)
67
-
([e] (eprint e)))))
89
+
(each stmt stmts (execute stmt)))
+3
-2
lox/main.janet
+3
-2
lox/main.janet
+2
-2
lox/parser.janet
+2
-2
lox/parser.janet
···
40
40
[:nil] [:literal nil]
41
41
[:num val] [:literal val]
42
42
[:str val] [:literal val]
43
-
[:ident name] [:variable name]
43
+
[:ident name] [:variable token]
44
44
[:left-paren] (do (def expr (expression parser))
45
45
(:consume parser :right-paren "Expect ')' after expression.")
46
46
[:grouping expr])))
···
90
90
(when (def equals (:match parser :eq))
91
91
(def value (assignment parser))
92
92
(match expr
93
-
[:variable name] (set expr [:assignment name value])
93
+
[:variable name] (set expr [:assign name value])
94
94
# TODO put equals token in error?
95
95
_ (errorf "Invalid assignment target: %M" expr)))
96
96
expr)
+28
test/test_main.janet
+28
test/test_main.janet
···
10
10
(test-stdout (process "if (false) print 1; else print 2;") `
11
11
2
12
12
`)
13
+
14
+
(test-stdout (process "var three = 1 + 2; print three;") `
15
+
3
16
+
`)
17
+
(test-stdout (process "var three; three = 1 + 2; print three;") `
18
+
3
19
+
`)
20
+
(test-stdout (process "var none = nil; print none;") `
21
+
nil
22
+
`)
23
+
(test-stdout (process `
24
+
var n = 1 + 2;
25
+
{
26
+
print n;
27
+
n = n * 10;
28
+
var n = -1;
29
+
n = n * 10;
30
+
print n;
31
+
}
32
+
n = n * 10;
33
+
print n;
34
+
`) `
35
+
3
36
+
-10
37
+
300
38
+
`)
39
+
(test-error (process "none = nil;") "Undefined variable 'none'.")
40
+
(test-error (process "print none;") "Undefined variable 'none'.")
+15
test/test_parser.janet
+15
test/test_parser.janet
···
1
1
(use judge)
2
+
(use ../lox/scanner)
2
3
(use ../lox/parser)
3
4
4
5
(defn parse [tokens] (:parse (make-parser tokens)))
···
50
51
[:literal true]
51
52
[:print [:literal true]]
52
53
[:print [:literal false]]]])
54
+
55
+
(defn scan-parse [input] (parse (scan input)))
56
+
57
+
(test (scan-parse "var three;")
58
+
@[[:var
59
+
{:line 1 :token [:ident "three"]}
60
+
nil]])
61
+
(test (scan-parse "var three = 1 + 2; print three;")
62
+
@[[:var {:line 1 :token [:ident "three"]}
63
+
[:binary
64
+
[:literal 1]
65
+
{:line 1 :token [:plus]}
66
+
[:literal 2]]]
67
+
[:print [:variable {:line 1 :token [:ident "three"]}]]])